#include "Spiel.h" #include #include #include "Define.h" #include "SSKlient.h" #include "KartenLeser.h" #include "Statistik.h" #include "Team.h" #include "Laser.h" #include #include #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; asteroids = new RCArray< Asteroid >(); asteroidModels = new RCArray< Model2DData >(); stat = new Statistik(); teams = new RCArray< Team >(); teamAnzahl = 0; spieler = new RCArray< Spieler >(); shots = new RCArray< Laser >(); objekte = new RCArray< SpielObjekt >(); welt = new Welt2D(); pixel = new RCArray< Pixel >(); welt->setCircular( 1 ); welt->setAirResistance( 0.001f ); psqldb = 0; spielId = 0; karteId = 0; spielerAnzahl = 0; karte = 0; InitializeCriticalSection( &cs ); sts = 0; log = 0; isRunning = 0; spielZeit = 0; ende = 1; nextSchussId = 1; nextAsteroid = 30; asteroidId = 0; pixelId = 0; ref = 1; } // Destruktor Spiel::~Spiel() { teams->release(); stat->release(); for( auto s = spieler->getIterator(); s; s++ ) s->setTeam( 0 ); spieler->release(); for( auto o = objekte->getIterator(); o; o++ ) o->setTeam( 0 ); objekte->release(); welt->release(); asteroids->release(); asteroidModels->release(); if( psqldb ) psqldb->release(); if( karte ) karte->release(); if( sts ) sts->release(); pixel->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() ); for( auto o = karte->getObjekte(); o; o++ ) { SpielObjekt *obj = karte->createObjekt( o->id ); obj->setTeam( teams->get( o->team - 1 ) ); welt->addObject( obj->getThis() ); objekte->add( obj ); } welt->setSize( karte->getSize().x, karte->getSize().y ); welt->setSize( 1 ); } 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( spielerNummern->get( i ) >= von && spielerNummern->get( i ) < bis ) { team = j; break; } von = bis; } tmp->setTeam( teams->get( team ) ); teams->z( team )->spieler->add( tmp ); } welt->addObject( tmp->getThis() ); 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 { 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; } case 0xA: // Use active skill { bytes++; char id = *bytes; len--; for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp && tmp->getAccountId() == accountId ) { if( !tmp->istAmLeben() ) break; tmp->useSkill( id ); for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *s = spieler->z( j ); if( s && s->zKlient() ) s->zKlient()->sendeUseSkillNachricht( tmp->getSpielerNummer(), id, spielZeit ); } 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 welt->tick( zeit ); // Spieler Updaten for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp ) { if( tmp->doNeedWiederbelebung() ) { // Wiederbelebung tmp->wiederbeleben(); for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *s = spieler->z( j ); if( s ) s->zKlient()->sendeWiederbelebung( tmp->getSpielerNummer(), spielZeit ); } } } } // Schüsse Collision int anz = shots->getEintragAnzahl(); 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, 0, 0 ); } welt->removeObject( tmp ); shots->remove( i ); anz--; i--; } else { // Schuss existiert noch int team = getTeamVonSpieler( tmp->getSpieler() ); for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *attacked = spieler->z( j ); if( attacked && attacked->zTeam() && attacked->zTeam()->id != team && attacked->istTreffer( tmp->getPosition() ) ) { // Treffer Spieler *attacker = 0; for( int k = 0; k < spielerAnzahl; k++ ) { Spieler *tmpS = spieler->z( k ); if( tmpS && tmpS->getSpielerNummer() == tmp->getSpieler() ) attacker = tmpS; } double intens = tmp->getIntensity() * ( ( tmp->getSpeed() - attacked->getSpeed() ).getLength() / 200 ); bool kill = attacked->nimmSchaden( intens, attacker ? attacker->getLevel() : 1 ); if( tmp->getSpeed().getLengthSq() > 0 ) attacked->impuls( tmp->getPosition() - tmp->getSpeed(), tmp->getSpeed() * 0.3f ); int skillP = attacker->getSkillP(); attacker->machSchaden( intens, attacked->getLevel() ); float erf = attacker->getEp(); if( kill ) attacker->addKill( attacked->getLevel() ); for( int k = 0; k < spielerAnzahl; k++ ) { Spieler *sp = spieler->z( k ); if( sp ) sp->zKlient()->sendeTreffer( tmp->getId(), attacked->getSpielerNummer(), spielZeit, erf, skillP ); if( kill && sp ) sp->zKlient()->sendeTod( attacked->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; } welt->removeObject( tmp ); shots->remove( i ); anz--; i--; break; } } int objektAnzahl = objekte->getEintragAnzahl(); for( int j = 0; j < objektAnzahl; j++ ) { SpielObjekt *attacked = objekte->z( j ); if( attacked && ( !attacked->zTeam() || attacked->zTeam()->id != team ) && attacked->doesCollideWithLaser() && attacked->istTreffer( tmp->getPosition() ) ) { // Treffer Spieler *attacker = 0; for( int k = 0; k < spielerAnzahl; k++ ) { Spieler *tmpS = spieler->z( k ); if( tmpS && tmpS->getSpielerNummer() == tmp->getSpieler() ) attacker = tmpS; } double intens = tmp->getIntensity() * ( ( tmp->getSpeed() - attacked->getSpeed() ).getLength() / 200 ); bool kill = attacked->nimmSchaden( intens, attacker ? attacker->getLevel() : 1 ); if( tmp->getSpeed().getLengthSq() > 0 ) attacked->impuls( tmp->getPosition() - tmp->getSpeed(), tmp->getSpeed() * 0.3f ); int skillP = attacker->getSkillP(); attacker->machSchaden( intens, attacked->getLevel(), attacked->doesShotAddEp() ); float erf = attacker->getEp(); if( kill ) attacker->addKill( attacked->getLevel(), attacked->doesShotAddEp() ); for( int k = 0; k < spielerAnzahl; k++ ) { Spieler *sp = spieler->z( k ); if( sp ) sp->zKlient()->sendeObjektTreffer( tmp->getId(), attacked->getObjektId(), spielZeit, erf, skillP ); if( kill && sp ) sp->zKlient()->sendeObjektTod( attacked->getObjektId(), 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; } welt->removeObject( tmp ); shots->remove( i ); anz--; i--; break; } } int aAnz = asteroids->getEintragAnzahl(); for( int j = 0; j < aAnz; j++ ) { Asteroid *a = asteroids->z( j ); Vertex pos; __int64 seed = randG.getSeed(); double intens = tmp->getIntensity() * ( ( tmp->getSpeed() - a->getSpeed() ).getLength() / 200 ); Asteroid * b = a->istTreffer( tmp, &randG, asteroidId, pos ); if( b ) { float erf = 0; int skillP = 0; for( int k = 0; k < spielerAnzahl; k++ ) { Spieler *s = spieler->z( k ); if( s && s->getSpielerNummer() == tmp->getSpieler() ) { s->addTreffer( (float)intens, 0 ); erf = s->getEp(); skillP = s->getSkillP(); } } for( int k = 0; k < spielerAnzahl; k++ ) { Spieler *s = spieler->z( k ); if( s ) s->zKlient()->sendeAsteroidTreffer( a->getId(), b->getId(), tmp->getId(), pos, seed, spielZeit, erf, skillP ); } welt->removeObject( tmp ); shots->remove( i ); if( b->getMasse() > intens * 50 ) { asteroids->add( (Asteroid *)b->getThis() ); welt->addObject( b ); } else { Pixel *p = new Pixel( b->getPosition(), b->getSpeed(), b->getMasse() / 50, pixelId++ ); welt->addObject( p->getThis() ); pixel->add( p ); for( int k = 0; k < spielerAnzahl; k++ ) { Spieler *s = spieler->z( k ); if( s ) s->zKlient()->sendePixel( b->getId(), p->getId(), spielZeit ); } b->release(); } if( a->getMasse() < intens * 50 ) { Pixel *p = new Pixel( a->getPosition(), a->getSpeed(), a->getMasse() / 50, pixelId++ ); welt->addObject( p->getThis() ); pixel->add( p ); for( int k = 0; k < spielerAnzahl; k++ ) { Spieler *s = spieler->z( k ); if( s ) s->zKlient()->sendePixel( a->getId(), p->getId(), spielZeit ); } welt->removeObject( a ); asteroids->remove( j-- ); aAnz--; } } } } } } // 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 ) { nextSchussId++; welt->addObject( nL->getThis() ); 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->getPosition(), nL->getSpeed(), nL->getIntensity(), spielZeit ); } } } } // Asteroiden nextAsteroid -= zeit; if( nextAsteroid <= 0 ) { nextAsteroid += 30 + (float)randG.rand() * 30; if( asteroids->getEintragAnzahl() < 30 ) { Vertex pos = Vertex( (float)randG.rand() * (float)welt->getWorldInfo().size.x, (float)randG.rand() * (float)welt->getWorldInfo().size.y ); Vertex speed = Vertex( (float)randG.rand() * 100, (float)randG.rand() * 100 ); float rot = 2 * (float)PI * (float)randG.rand(); float rotS = (float)randG.rand(); int index = (int)( (float)asteroidModels->getEintragAnzahl() * (float)randG.rand() ); Asteroid *astr = new Asteroid( asteroidId++, pos, speed, rot, rotS, asteroidModels->get( index ) ); asteroids->add( astr ); welt->addObject( astr->getThis() ); for( int j = 0; j < spielerAnzahl; j++ ) { if( spieler->z( j ) && spieler->z( j )->zKlient() ) spieler->z( j )->zKlient()->sendeAsteroid( astr->getId(), pos, speed, rot, rotS, index, spielZeit ); } } } // Pixel int pixelAnz = pixel->getEintragAnzahl(); for( int i = 0; i < pixelAnz; i++ ) { Pixel *p = pixel->z( i ); if( p->getEp() <= 0 ) { for( int j = 0; j < spielerAnzahl; j++ ) { if( spieler->z( j ) && spieler->z( j )->zKlient() ) spieler->z( j )->zKlient()->sendeEp( p->getId(), -1, spielZeit ); } pixel->remove( i-- ); welt->removeObject( p ); pixelAnz--; } else { for( auto s = spieler->getIterator(); s; s++ ) { if( s->istTreffer( p->getPosition() ) ) { s->addEp( p->getEp() ); for( int j = 0; j < spielerAnzahl; j++ ) { if( spieler->z( j ) && spieler->z( j )->zKlient() ) spieler->z( j )->zKlient()->sendeEp( p->getId(), s->getSpielerNummer(), spielZeit ); } pixel->remove( i-- ); welt->removeObject( p ); pixelAnz--; break; } } } } } void Spiel::run() { Text *pfad = psqldb->getSpielPfad( karteId ); if( pfad ) pfad->append( "/" ); pfad->append( "models/asteroids.m2" ); M2Datei *aDat = new M2Datei(); aDat->setPfadZ( pfad ); aDat->leseDaten(); int anz = aDat->getModelAnzahl(); for( int i = 0; i < anz; i++ ) { asteroidModels->add( aDat->ladeModel( aDat->zModelName( i )->getText() ) ); } log = new Datei(); 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->addSkill( new ShieldBoost() ); tmp->addSkill( new SpeedBoost() ); tmp->zKlient()->sendeInit( spieler, -1 ); log->schreibe( (char *)& i, 4 ); int sNum = tmp->getSpielerNummer(); log->schreibe( (char *)& sNum, 4 ); tmp->zKlient()->sendeSpielerNummer( sNum, -1 ); 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 ); } } __int64 randSeed = randG.getSeed(); log->schreibe( (char *)& randSeed, 8 ); Array< char > spielerStatus; ZeitMesser * zeit = new ZeitMesser(); zeit->messungStart(); isRunning = 1; ende = 0; double ausgleich = 0; double sZ = 0; spielZeit = -1; for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler->z( i ); if( tmp && tmp->zKlient() ) tmp->zKlient()->sendeStart( spielZeit ); } double rZeit = 0; while( !ende ) { zeit->messungEnde(); zeit->messungStart(); double z = zeit->getSekunden(); ausgleich += TICK - 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; }