#include "Spiel.h" #include "DrachenAuge.h" #include "Brand.h" #define TICK 0.03333333 // Konstruktor Spiel::Spiel() { nextId = 0; isRunning = 0; log = 0; spielerAnzahl = 0; zAccounts = 0; spielId = 0; karteId = 0; pause = 0; gameTicks = 0; ende = 1; stat = new Statistik(); ref = 1; } // Destruktor Spiel::~Spiel() { stat->release(); if( psqldb ) psqldb->release(); } // nicht constant void Spiel::setPSQLK( SSDatenbankV *psqldb ) { if( this->psqldb ) this->psqldb->release(); this->psqldb = psqldb; stat->setPSQLDB( psqldb->getThis() ); } // call 1 void Spiel::setSpielId( int id ) { spielId = id; stat->setSpielId( id ); } // call 2 void Spiel::setKarteId( int karteId ) { this->karteId = karteId; stat->setKarteId( karteId ); } // call 3 void Spiel::setTempPfad( char *pfad ) { mapPfad = pfad; mapPfad += "/"; } // call 3.5 void Spiel::setAccounts( int anzahl, Array< int > *zAccounts ) { this->zAccounts = zAccounts->getThis(); spielerAnzahl = anzahl; } // call 4 void Spiel::setKlients( int anzahl, RCArray< SSKlientV > *zKlients ) { this->zKlients = zKlients->getThis(); } // call 5 void Spiel::setSpielerNummern( int anzahl, Array< int > *spielerNummern ) { MapReader *reader = new MapReader( karteId, psqldb->getThis(), mapPfad ); reader->ladeKarte( this ); reader->release(); for( int i = 0; i < anzahl; i++ ) { for( auto s = spieler.getIterator(); s; s++ ) { if( s->getSpielerNummer() == spielerNummern->get( i ) ) { s->setAccount( zAccounts->get( i ) ); s->setKlient( new Klient( zKlients->get( i ) ) ); break; } } } zAccounts = zAccounts->release(); zKlients = zKlients->release(); stat->setTeams( spielerAnzahl, &teams ); stat->setSpieler( spielerAnzahl, &spieler ); } // call 6 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, -1 ); log->schreibe( (char *)& i, 4 ); int sNum = tmp->getSpielerNummer(); log->schreibe( (char *)& sNum, 4 ); tmp->zKlient()->sendeSpielerNummer( sNum, -1 ); 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(); } } __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; gameTicks = -1; for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler.z( i ); if( tmp && tmp->zKlient() ) tmp->zKlient()->sendeStart( gameTicks ); } throwEvent( new Ereignis( INITIALISIERUNG ) ); 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 ) { c.lock(); sZ += TICK; gameTicks++; char ch = 0; log->schreibe( &ch, 1 ); tick( TICK ); c.unlock(); } } zeit->messungEnde(); zeit->release(); for( int i = 0; i < spielerAnzahl; i++ ) { if( spieler.z( i ) && spieler.z( i )->zKlient() ) { if( !spieler.z( i )->zTeam()->getPunkte() ) { 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 )->zKlient()->istOnline() ) ) spielerStatus.set( 3, i ); } 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 ) ); psqldb->addSpielerStatistik( tmp->getAccountId(), spielId ); } } log->close(); log = log->release(); isRunning = 0; } // call 7 void Spiel::klientOffline( int accountId ) { for( int i = 0; i < spielerAnzahl; i++ ) { if( spieler.z( i )->getAccountId() == accountId ) spieler.z( i )->zKlient()->offline(); } } void Spiel::klientOnline( int accountId, SSKlientV * zKlient ) { for( int i = 0; i < spielerAnzahl; i++ ) { if( spieler.z( i )->getAccountId() == accountId ) { c.lock(); Spieler *s = spieler.z( i ); Klient *tmp = s->zKlient(); tmp->online( zKlient ); tmp->sendeSpielerNummer( s->getSpielerNummer(), 0 ); //-------------------------- c.unlock(); } } } void Spiel::nachricht( int accountId, int len, char *bytes ) { if( !isRunning ) return; c.lock(); if( ende ) { c.unlock(); return; } char *msgBeg = bytes; int msgLen = len; int msgAccount = accountId; bool saveMSG = 1; len--; switch( *bytes ) { case 0: // key press bytes++; len--; for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler.z( i ); if( tmp && tmp->getAccountId() == accountId ) { if( !tmp->setTastenStand( *bytes, 1 ) ) { saveMSG = 0; break; } Ereignis *e = new Ereignis( SPIELER_KEY_PRESSED ); char buff[] = { *bytes, 0 }; e->addParameter( "Betroffene Taste", new String( buff ) ); e->addParameter( "Ausführender Spieler", tmp->getThis() ); throwEvent( e ); for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *s = spieler.z( j ); if( s && s->zKlient() ) s->zKlient()->sendeTastaturStatus( tmp->getSpielerNummer(), *bytes, 1, gameTicks ); } break; } } break; case 1: // key release bytes++; len--; for( int i = 0; i < spielerAnzahl; i++ ) { Spieler *tmp = spieler.z( i ); if( tmp && tmp->getAccountId() == accountId ) { if( !tmp->setTastenStand( (unsigned char)*bytes, 0 ) ) { saveMSG = 0; break; } Ereignis *e = new Ereignis( SPIELER_KEY_RELEASED ); char buff[] = { *bytes, 0 }; e->addParameter( "Betroffene Taste", new String( buff ) ); e->addParameter( "Ausführender Spieler", tmp->getThis() ); throwEvent( e ); for( int j = 0; j < spielerAnzahl; j++ ) { Spieler *s = spieler.z( j ); if( s && s->zKlient() ) s->zKlient()->sendeTastaturStatus( tmp->getSpielerNummer(), *bytes, 0, gameTicks ); } break; } } break; case 3: // 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(), gameTicks ); } 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 ); } c.unlock(); } void Spiel::setMapSize( int width, int height ) { mapSize = Punkt( width, height ); } void Spiel::setPausiert( bool pausiert ) { this->pause = pausiert; } void Spiel::tick( double zeit ) { if( pause ) zeit = 0; // spieler bewegungen for( auto s = spieler.getIterator(); s; s++ ) { s->move( zeit ); if( s->getX() < 0 || s->getY() < 0 || s->getX() + s->getWidth() >= mapSize.x || s->getY() + s->getHeight() >= mapSize.y ) s->move( -zeit ); else { for( auto b = barieren.getIterator(); b; b++ ) { // spieler - bariere intersection if( b->hatStyle( Bariere::Style::Aktiv ) && ( b->zTeam() != s->zTeam() ) && b->intersectsWith( s ) ) s->move( -zeit ); } } } for( auto s = spieler.getIterator(); s; s++ ) s->tick( zeit, this ); // barieren bewegung for( auto b = barieren.getIterator(); b; b++ ) b->tick( zeit, this ); // geschoss bewegung for( int i = 0; i < shots.getEintragAnzahl(); i++ ) { Geschoss *g = shots.z( i ); g->tick( zeit ); bool removed = 0; // geschoss - bariere intersection bool intersectsWithBariere = 0; for( auto b = barieren.getIterator(); b; b++ ) { if( b->hatStyle( Bariere::Style::Aktiv ) && b->intersectsWith( g ) ) { intersectsWithBariere = 1; break; } } if( intersectsWithBariere || g->getX() < 0 || g->getY() < 0 || g->getX() + g->getWidth() >= mapSize.x || g->getY() + g->getHeight() >= mapSize.y ) { g->tick( -zeit ); switch( g->getTyp() ) { case GESCHOSS_PFEIL: shots.remove( i ); i--; removed = 1; break; case GESCHOSS_KUGEL: case GESCHOSS_DRACHENAUGE: g->invertDirection(); break; case GESCHOSS_FEUERBALL: if( intersectsWithBariere ) { feuer.add( new FeuerballTreffer( ++nextId, (int)g->getX() - 70, (int)g->getY() - 70, g->getBesitzer(), 10 ) ); shots.remove( i ); i--; removed = 1; } else g->invertDirection(); break; case GESCHOSS_MINE: for( auto s = spieler.getIterator(); s; s++ ) { if( s->abstandZu( g ) < 50 ) { s->nimmSchaden( 100 - s->abstandZu( g ), g->zBesitzer(), MITTE, this ); if( g->zBesitzer() ) g->zBesitzer()->addTreffer( this ); s->addGetroffen(); } } shots.remove( i ); i--; removed = 1; break; } } if( !removed ) { // geschoss - tunnel intersection for( auto t = tunnel.getIterator(); t; t++ ) { if( t->istAktiv() && t->intersectsWith( g ) ) { g->setX( g->getX() + (float)t->getZielX() - t->getX() ); g->setY( g->getY() + (float)t->getZielY() - t->getY() ); g->addTunnel(); Ereignis *e = new Ereignis( TUNNEL_BENUTZT ); e->addParameter( "Betroffes Geschoss", g->getThis() ); e->addParameter( "Betroffer Tunnel", t->getThis() ); throwEvent( e ); } } // geschoss - schalter intersection if( g->getTyp() == GESCHOSS_PFEIL ) { for( auto s = schalter.getIterator(); s; s++ ) { if( s->isAktive() && s->intersectsWith( g ) ) { shots.remove( i ); i--; removed = 1; g->addSchalter(); activateShalter( s->getId() ); } } } if( !removed ) { // geschoss - umlenkung intersection if( g->getTyp() != GESCHOSS_PFEIL ) { for( auto u = umlenkungen.getIterator(); u; u++ ) { if( u->isAktive() && !u->hatAbklingzeit() && g->getTyp() != GESCHOSS_PFEIL && u->intersectsWith( g ) ) { g->setRichtung( u->getRichtung() ); g->addUmlenkung(); u->addBenutzt(); Ereignis *e = new Ereignis( UMLENKUNG_LENKT_UM ); e->addParameter( "Betroffes Geschoss", g->getThis() ); e->addParameter( "Betroffe Umlenkung", u->getThis() ); throwEvent( e ); } } } // geschoss - geschoss intersection if( g->getTyp() == GESCHOSS_PFEIL ) { for( int j = 0; j < shots.getEintragAnzahl(); j++ ) { if( i == j ) continue; Geschoss *g2 = shots.z( j ); if( g2->intersectsWith( g ) ) { if( g2->getTyp() == GESCHOSS_PFEIL ) removed = 1; g->addGeschossTreffer(); if( j < i ) i--; shots.remove( j ); } } } if( !removed ) { // geschoss - spieler intersection for( auto s = spieler.getIterator(); s; s++ ) { if( s->istAmLeben() && s != g->zBesitzer() && g->intersectsWith( s ) ) { switch( g->getTyp() ) { case GESCHOSS_PFEIL: { s->nimmSchaden( PFEIL_DAMAGE, g->zBesitzer(), invert( g->getRichtung() ), this ); break; } case GESCHOSS_KUGEL: { s->nimmSchaden( KUGEL_DAMAGE, g->zBesitzer(), invert( g->getRichtung() ), this ); break; } case GESCHOSS_DRACHENAUGE: s->addEffekt( new DrachenAugeEffect( g->zBesitzer(), s._ ) ); break; case GESCHOSS_FEUERBALL: feuer.add( new FeuerballTreffer( ++nextId, (int)g->getX() - 70, (int)g->getY() - 70, g->getBesitzer(), 10 ) ); break; case GESCHOSS_MINE: for( auto s2 = spieler.getIterator(); s2; s2++ ) { if( s2->abstandZu( g ) < 50 ) { s2->nimmSchaden( 100 - s->abstandZu( g ), g->zBesitzer(), MITTE, this ); if( g->zBesitzer() ) g->zBesitzer()->addTreffer( this ); s->addGetroffen(); } } break; } if( g->getTyp() != GESCHOSS_MINE ) { if( g->zBesitzer() ) g->zBesitzer()->addTreffer( this ); s->addGetroffen(); } shots.remove( i ); i--; removed = 1; } } } } } } // Feuer Ticks for( int i = 0; i < feuer.getEintragAnzahl(); i++ ) { FeuerballTreffer *f = feuer.z( i ); f->tick( zeit ); if( f->isOver() ) { feuer.remove( i ); i--; continue; } if( f->makeDamage() ) { for( auto s = spieler.getIterator(); s; s++ ) { if( s->abstandZu( f ) < f->getWidth() / 2 ) s->addEffekt( new BrandEffekt( f->zVerursacher(), s ) ); } } } // Drop Ticks for( auto d = drops.getIterator(); d; d++ ) d->tick( zeit, this ); // Timer Ticks for( auto t = timer.getIterator(); t; t++ ) t->tick( zeit, this ); // Umlenkung Ticks for( auto u = umlenkungen.getIterator(); u; u++ ) u->tick( zeit ); // Base Ticks for( auto b = basen.getIterator(); b; b++ ) b->tick( zeit, this ); // aktive trigger Ticks for( int i = 0; i < triggerRuns.getEintragAnzahl(); i++ ) { if( !triggerRuns.z( i )->runNext( zeit ) ) { Ereignis *e = new Ereignis( AUSLOESER_RUNNED ); e->addParameter( "Betroffener Auslöser", triggerRuns.z( i )->getTrigger() ); throwEvent( e ); triggerRuns.remove( i ); i--; } } } void Spiel::addVariable( const char *name, Variable * var ) { bool found = 0; for( auto v = variablen.getIterator(); v; v++ ) { if( v->getName().istGleich( name ) ) { found = 1; break; } } if( !found ) variablen.add( new VarPointer( name, var ) ); else var->release(); } void Spiel::setVariable( const char *name, Variable * var ) { bool found = 0; for( auto v = variablen.getIterator(); v; v++ ) { if( v->getName().istGleich( name ) ) { v->setVariable( var ); break; } } if( !found ) var->release(); } void Spiel::addTeam( Team * team ) { teams.add( team ); } void Spiel::addSpieler( Spieler * spieler ) { this->spieler.add( spieler ); } void Spiel::addBariere( Bariere * bariere ) { barieren.add( bariere ); } void Spiel::addBase( Base * base ) { basen.add( base ); } void Spiel::addDrop( Drop * drop ) { drops.add( drop ); } void Spiel::addGegenstand( Gegenstand * gegenstand ) { items.add( gegenstand ); Ereignis *e = new Ereignis( GEGENSTAND_DROPED ); e->addParameter( "Betroffener Gegenstand", gegenstand->getThis() ); throwEvent( e ); } void Spiel::addGeschoss( Geschoss * geschoss ) { shots.add( geschoss ); } void Spiel::addSchalter( Schalter * schalter ) { this->schalter.add( schalter ); } void Spiel::addSchiene( Schiene * schiene ) { schienen.add( schiene ); } void Spiel::addTimer( Timer * timer ) { this->timer.add( timer ); } void Spiel::addTunnel( Tunnel * tunnel ) { this->tunnel.add( tunnel ); } void Spiel::addUmlenkung( Umlenkung * umlenkung ) { umlenkungen.add( umlenkung ); } void Spiel::addTrigger( Trigger * trigger ) { this->trigger.add( trigger ); } void Spiel::addTriggerRun( TriggerRun * tRun ) { triggerRuns.add( tRun ); } Team *Spiel::getTeam( int id ) const { for( auto t = teams.getIterator(); t; t++ ) { if( t->getTeamNummer() == id ) return (Team *)t->getThis(); } return 0; } Spieler *Spiel::getSpieler( int id ) const { for( auto s = spieler.getIterator(); s; s++ ) { if( s->getId() == id ) return (Spieler*)s->getThis(); } return 0; } Iterator Spiel::getSpieler() const { return spieler.getIterator(); } Iterator Spiel::getBarieren() const { return barieren.getIterator(); } Bariere *Spiel::getBariere( int id ) const { for( auto b = barieren.getIterator(); b; b++ ) { if( b->getId() == id ) return (Bariere *)b->getThis(); } return 0; } Base *Spiel::getBase( int id ) const { for( auto b = basen.getIterator(); b; b++ ) { if( b->getId() == id ) return (Base *)b->getThis(); } return 0; } Drop *Spiel::getDrop( int id ) const { for( auto d = drops.getIterator(); d; d++ ) { if( d->getId() == id ) return (Drop *)d->getThis(); } return 0; } Schalter *Spiel::getSchalter( int id ) const { for( auto s = schalter.getIterator(); s; s++ ) { if( s->getId() == id ) return (Schalter *)s->getThis(); } return 0; } Schiene *Spiel::getSchiene( int id ) const { for( auto s = schienen.getIterator(); s; s++ ) { if( s->getId() == id ) return (Schiene *)s->getThis(); } return 0; } Timer *Spiel::getTimer( int id ) const { for( auto t = timer.getIterator(); t; t++ ) { if( t->getId() == id ) return (Timer *)t->getThis(); } return 0; } Tunnel *Spiel::getTunnel( int id ) const { for( auto t = tunnel.getIterator(); t; t++ ) { if( t->getId() == id ) return (Tunnel *)t->getThis(); } return 0; } Umlenkung *Spiel::getUmlenkung( int id ) const { for( auto u = umlenkungen.getIterator(); u; u++ ) { if( u->getId() == id ) return (Umlenkung *)u->getThis(); } return 0; } Trigger *Spiel::getTrigger( int id ) const { for( auto t = trigger.getIterator(); t; t++ ) { if( t->getId() == id ) return (Trigger *)t->getThis(); } return 0; } Variable *Spiel::getVariable( const char *name ) const { for( auto v = variablen.getIterator(); v; v++ ) { if( v->getName().istGleich( name ) ) return v->getVariable(); } return 0; } Variable *Spiel::zVariable( const char *name ) const { for( auto v = variablen.getIterator(); v; v++ ) { if( v->getName().istGleich( name ) ) return v->zVariable(); } return 0; } bool Spiel::istPausiert() const { return pause; } void Spiel::activateShalter( int id ) { for( auto s = schalter.getIterator(); s; s++ ) { if( s->getId() == id ) { s->press(); Ereignis *e = new Ereignis( SCHALTER_AKTIVIERT ); e->addParameter( "Betroffener Schalter", s->getThis() ); throwEvent( e ); } } } void Spiel::throwEvent( Ereignis *e ) { for( auto t = trigger.getIterator(); t; t++ ) { if( t->hatEreignis( e->getTyp() ) ) triggerRuns.add( t->runTrigger( e->getThis(), this ) ); } e->release(); } bool Spiel::needEvent( EreignisTyp typ ) const { for( auto t = trigger.getIterator(); t; t++ ) { if( t->hatEreignis( typ ) ) return 1; } return 0; } int Spiel::getNextId() { return ++nextId; } double Spiel::getRand() { return randG.rand(); } int Spiel::getTickCount() const { return gameTicks; } StatistikV *Spiel::getStatistik() const { return stat->getThis(); } // Reference Counting SpielKlasse *Spiel::getThis() { ref++; return this; } SpielKlasse *Spiel::release() { if( !--ref ) delete this; return 0; }