#include "Spiel.h" #include #include #include "Define.h" #include "SSKlient.h" #include "KartenLeser.h" #include "Statistik.h" #include "Team.h" #include "Laser.h" #ifdef WIN32 #include #else #include #include #include #define Sleep( x ) usleep( (x) * 1000 ) #endif // Inhalt der Spiel Klasse aus Spiel.h // Konstruktor Spiel::Spiel() { zAccounts = 0; zKlients = 0; stat = new Statistik(); teams = new RCArray< Team >(); teamAnzahl = 0; spieler = new RCArray< Spieler >(); shots = new RCArray< Laser >(); objekte = new RCArray< SpielObjekt >(); psqldb = 0; spielId = 0; karteId = 0; spielerAnzahl = 0; karte = 0; InitializeCriticalSection( &cs ); sts = 0; log = 0; isRunning = 0; spielZeit = 0; ende = 1; nextSchussId = 1; ref = 1; } // Destruktor Spiel::~Spiel() { teams->release(); stat->release(); spieler->release(); objekte->release(); if( psqldb ) psqldb->release(); if( karte ) karte->release(); if( sts ) sts->release(); DeleteCriticalSection( &cs ); } // privat int Spiel::getTeamVonSpieler( int sNum ) { for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp && tmp->getSpielerNummer() == sNum ) return tmp->zTeam() ? tmp->zTeam()->id : 0; } return 0; } // nicht constant void Spiel::setPSQLK( SSDatenbankV *psqldb ) { if( this->psqldb ) this->psqldb->release(); this->psqldb = psqldb; stat->setPSQLDB( psqldb->getThis() ); } void Spiel::setSpielId( int id ) { spielId = id; stat->setSpielId( id ); } void Spiel::setKarteId( int karteId ) { this->karteId = karteId; stat->setKarteId( karteId ); } void Spiel::setTempPfad( char *pfad ) { mapPfad = pfad; mapPfad += "/"; } void Spiel::setAccounts( int anzahl, Array< int > *zAccounts ) { this->zAccounts = zAccounts->getThis(); spielerAnzahl = anzahl; } void Spiel::setKlients( int anzahl, RCArray< SSKlientV > *zKlients ) { this->zKlients = zKlients->getThis(); } void Spiel::setSpielerNummern( int anzahl, Array< int > *spielerNummern ) { if( !sts ) { sts = new SpielerTeamStruktur(); KartenLeser *reader = new KartenLeser( karteId, psqldb->getThis(), mapPfad ); reader->ladeSpielerTeamStruktur( sts ); if( karte ) karte->release(); karte = reader->ladeKarte( sts ); reader->release(); for( int i = 0; i < sts->teamAnzahl; i++ ) teams->set( karte->createTeam( i ), i ); stat->setTeamNamen( sts->teamName->getThis() ); int objektAnzahl = karte->getObjektAnzahl(); for( int i = 0; i < objektAnzahl; i++ ) objekte->set( karte->createObjekt( i ), i ); } for( int i = 0; i < anzahl; i++ ) { Spieler *tmp = karte->createSpieler( spielerNummern->get( i ) ); if( tmp ) { 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( tmp->getSpielerNummer() >= von && tmp->getSpielerNummer() < bis ) { team = j; break; } von = bis; } tmp->setTeam( teams->get( team ) ); teams->z( team )->spieler->add( tmp ); } spieler->set( tmp, i ); } for( int i = 0; i < anzahl; i++ ) spieler->z( i )->setAccountId( zAccounts->hat( i ) ? zAccounts->get( i ) : 0 ); for( int i = 0; i < anzahl; i++ ) spieler->z( i )->setKlient( new Klient( zKlients->get( i ) ) ); stat->setSpieler( spielerAnzahl, spieler ); zAccounts = zAccounts->release(); zKlients = zKlients->release(); teamAnzahl = 0; for( int i = 0; i < sts->teamAnzahl; i++ ) if( teams->z( i )->spieler->getEintragAnzahl() ) teamAnzahl++; } 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 ); //-------------------------- 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: case 1: case 2: case 3: case 4: case 5: case 6: case 7: for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp && tmp->getAccountId() == accountId ) { if( !tmp->istAmLeben() ) break; if( !tmp->setTastataturStatus( (TastaturStatus)( (int)( *bytes ) / 2 ), ( (int)( *bytes ) % 2 ) == 0 ) ) { saveMSG = 0; break; } if( *bytes != 6 && *bytes != 7 ) { for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *s = spieler->z( j ); if( s && s->zKlient() ) s->zKlient()->sendeTastaturStatus( tmp->getSpielerNummer(), (TastaturStatus)( (int)( *bytes ) / 2 ), ( (int)( *bytes ) % 2 ) == 0, spielZeit ); } } break; } } break; case 8: // 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; case 9: // Skill verwendung if( 1 ) { bytes++; char art = *bytes; len--; for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp && tmp->getAccountId() == accountId ) { if( !tmp->istAmLeben() ) break; if( !tmp->setSkill( art ) ) { saveMSG = 0; break; } for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *s = spieler->z( j ); if( s && s->zKlient() ) s->zKlient()->sendeSkillNachricht( tmp->getSpielerNummer(), art, spielZeit ); } break; } } break; } 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 ) { // Objekte Updaten int objektAnzahl = objekte->getEintragAnzahl(); for( int i = 0; i < objektAnzahl; i++ ) objekte->z( i )->tick(); // Spieler Updaten for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp ) { if( tmp->tick( zeit, karte ) == 1 ) { // Wiederbelebung for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *s = spieler->z( j ); if( s ) s->zKlient()->sendeWiederbelebung( tmp->getSpielerNummer(), spielZeit ); } } } } // Schüsse Updaten int anz = shots->getEintragAnzahl(); for( int i = 0; i < anz; i++ ) { if( shots->z( i ) ) shots->z( i )->tick( zeit, karte ); } // Schüsse Collision for( int i = 0; i < anz; i++ ) { Laser *tmp = shots->z( i ); if( tmp ) { if( tmp->getIntensity() <= 0 ) { // Schuss existiert nicht mehr for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *s = spieler->z( j ); if( s ) s->zKlient()->sendeTreffer( tmp->getId(), -1, spielZeit ); } shots->remove( i ); anz--; i--; } else { // Schuss existiert noch int team = getTeamVonSpieler( tmp->getSpieler() ); for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *s = spieler->z( j ); if( s && s->zTeam() && s->zTeam()->id != team && ( s->istTreffer( tmp->getPos() ) || s->istTreffer( tmp->getPos() + karte->getSize() ) || s->istTreffer( tmp->getPos() - karte->getSize() ) ) ) { // Treffer bool kill = s->nimmSchaden( tmp->getIntensity() * ( (tmp->getSpeed() - s->getSpeed() ).getLength() / 200 ) ); for( int k = 0; k < spielerAnzahl; k++ ) { Spieler *sp = spieler->z( k ); if( sp ) sp->zKlient()->sendeTreffer( tmp->getId(), s->getSpielerNummer(), spielZeit ); if( sp && sp->getSpielerNummer() == tmp->getSpieler() ) sp->machSchaden( tmp->getIntensity() * ( (tmp->getSpeed() - s->getSpeed() ).getLength() / 200 ), kill ); if( kill && sp ) sp->zKlient()->sendeTod( s->getSpielerNummer(), tmp->getSpieler(), spielZeit ); } if( kill ) { if( teams->z( team - 1 ) ) teams->z( team - 1 )->punkte++; if( teams->z( team - 1 )->punkte == teams->z( team - 1 )->maxPunkte ) ende = 1; } shots->remove( i ); anz--; i--; break; } } } } } // Neue Schüsse hinzufügen for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp ) { Laser *nL = tmp->getLaser( nextSchussId++ ); if( nL ) { shots->add( nL ); for( int j = 0; j < spielerAnzahl; j++ ) { if( spieler->z( j ) && spieler->z( j )->zKlient() ) spieler->z( j )->zKlient()->sendeSchuss( nL->getId(), nL->getSpieler(), nL->getPos(), nL->getSpeed(), nL->getIntensity(), spielZeit ); } } } } } 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() ) { tmp->zKlient()->sendeInit( spieler, 0 ); log->schreibe( (char*)&i, 4 ); int sNum = tmp->getSpielerNummer(); log->schreibe( (char*)&sNum, 4 ); tmp->zKlient()->sendeSpielerNummer( sNum, 0 ); int team = tmp->zTeam()->id; log->schreibe( (char*)&team, 4 ); int farbe = tmp->getSpielerFarbe(); log->schreibe( (char*)&farbe, 4 ); farbe = tmp->zTeam()->farbe; 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( team ); len = (char)( name ? name->getLength() : 0 ); log->schreibe( &len, 1 ); if( len ) log->schreibe( name->getText(), len ); } } Array< char > spielerStatus; ZeitMesser *zeit = new ZeitMesser(); zeit->messungStart(); isRunning = 1; ende = 0; double ausgleich = 0; double sZ = 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( sZ + TICK < rZeit && !ende ) { EnterCriticalSection( &cs ); sZ += TICK; spielZeit++; char c = 0; log->schreibe( &c, 1 ); tick( TICK ); LeaveCriticalSection( &cs ); } } zeit->messungEnde(); zeit->release(); for( int i = 0; i < spielerAnzahl; i++ ) { if( spieler->z( i ) && spieler->z( i )->zKlient() ) { if( spieler->z( i )->zTeam()->punkte < spieler->z( i )->zTeam()->maxPunkte ) { spielerStatus.set( 1, i ); // Datenbank Verloren spieler->z( i )->zKlient()->sendeSpielEnde( 0, 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 ); } 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 = log->release(); isRunning = 0; } // constant StatistikV *Spiel::getStatistik() const { return stat->getThis(); } // Reference Counting SpielKlasse *Spiel::getThis() { ref++; return this; } SpielKlasse *Spiel::release() { ref--; if( !ref ) delete this; return 0; }