// Hakkeri-olion toteutus #include "hakkeri.hh" #include #include using std::endl; // MOODIKUVAUKSET-taulukon sisältö. const std::string Hakkeri::MOODIKUVAUKSET[] = {"Irkkaa", "Koodaa", "Reitittää", "Puskuroi", "Terassilla"}; // Hakkerin rakentaja, joka ottaa yleisasetukset sekä hakkeriryhmätiedostosta // luetut tiedot Hakkeri::Hakkeri(const Asetukset &asetukset, const std::string &nimi, int maxkola, int maxhermot): asetukset_(asetukset), nimi_(nimi), tila_(PERUS), virustaso_(0), reitityskohteet_(), reititysvuoro_(0), maara_(0), kola_(maxkola), hermot_(maxhermot), maxkola_(maxkola), maxhermot_(maxhermot) { } // Palauttaa hakkerin nimen std::string Hakkeri::haeNimi() const { return nimi_; } // Onko hakkerin tila jokin muu kuin OFFLINE? bool Hakkeri::online() const { return tila_ != OFFLINE; } // Vuoron alussa tehtävä kolanlisäys. void Hakkeri::lisaaKolaa() { kola_ += (asetukset_.kolauusiutuminen * maxkola_) / 100; if (kola_ > maxkola_) { kola_ = maxkola_; } } // Vastaanottaa viruksen ja suorittaa tilan perusteella toimenpiteitä. void Hakkeri::otaVirus(int taso, std::ostream &out) { out << nimi_ << " saa tason " << taso << " viruksen koneelleen!" << endl; Hakkeri *kohde = NULL; switch (tila_) { case PERUS: case HYOKKAYS: kulutaHermoja(taso, out); break; case PUSKUROINTI: out << nimi_ << " puskuroi viruksen!" << endl; virustaso_ += taso; maara_ -= 1; if (maara_ <= 0) { tila_ = HYOKKAYS; // Ei nollata muuttujia. out << nimi_ << " on täyttänyt puskurinsa viruksilla."; out << endl; } break; case REITITYS: kohde = reitityskohteet_.at(reititysvuoro_); reititysvuoro_ = (reititysvuoro_ + 1) % reitityskohteet_.size(); out << nimi_ << " reitittää viruksen kohti hakkerin "; out << kohde->haeNimi() << " konetta!" << endl; maara_ -= 1; if (maara_ <= 0) { vaihdaTila(PERUS); out << nimi_ << " purkaa reitityksensä!" << endl; } kohde->otaVirus(taso, out); break; case OFFLINE: out << nimi_ << " on terassilla. Häntä ei kiinnosta." << endl; break; default: // Tänne ei pitäisi päätyä. throw std::invalid_argument("Virheellinen hakkeritila"); } } // Suorittaa siirron. Palauttaa true jos vuoro jatkuu. bool Hakkeri::suoritaSiirto(const Siirto &siirto, std::ostream &out) { // Kaikissa tulosteissa aluksi hakkerin nimi out << nimi_ << " "; // Temppimuuttuja joitakin caseja varten int virustaso = 0; switch (siirto.tyyppi) { case KOODAA: out << "koodaa tason " << siirto.maara << " viruksen." << endl; vaihdaTila(HYOKKAYS); virustaso_ = siirto.maara; break; case PUSKUROI: out << "valmistautuu puskuroimaan sisääntulevia viruksia."; out << endl; vaihdaTila(PUSKUROINTI); maara_ = siirto.maara; break; case REITITA: out << "valmistautuu reitittämään sisääntulevia viruksia."; out << endl; vaihdaTila(REITITYS); maara_ = siirto.maara; reitityskohteet_ = siirto.reitityskohteet; reititysvuoro_ = 0; break; case RESETOI: out << "buuttaa koneensa." << endl; vaihdaTila(PERUS); break; case HYOKKAA: out << "hyökkää kohteenaan " << siirto.kohde->haeNimi() << "!"; out << endl; virustaso = virustaso_; // Viruksen taso talteen. vaihdaTila(PERUS); siirto.kohde->otaVirus(virustaso, out); break; case TANKKAA: out << "ottaa rennosti ja tankkaa kolaa." << endl; // Tankattaessa annetaan kolamäärä, ei hermomäärää. hermot_ += siirto.maara / asetukset_.tankkauskulutus; if (hermot_ >= maxhermot_) { hermot_ = maxhermot_; } break; case ODOTA: out << "odottaa oikeaa hetkeä idlaten irkissä." << endl; break; default: // Tänne ei pitäisi päätyä. throw std::invalid_argument("Virheellinen siirtotyyppi"); } kulutaKolaa(laskeKulutus(siirto, asetukset_), out); // Vain TANKKAA:n jälkeen vuoro ei vaihdu. return (siirto.tyyppi == TANKKAA); } // Tarkistaa siirron kelvollisuuden nykyisessä tilanteessa. bool Hakkeri::tarkistaSiirto(const Siirto &siirto, std::ostream &err) const { // Tarkistetaan että siirron tyyppi on määritelty. if (siirto.tyyppi == EISIIRTOA) { // Tänne ei pitäisi päätyä. throw std::invalid_argument("Virheellinen siirtotyyppi"); } if (siirto.tyyppi == HYOKKAA && virustaso_ == 0) { err << "Virhe: " << nimi_ << " ei omista virusta." << endl; return false; } if (siirto.tyyppi == TANKKAA && tila_ != PERUS) { err << "Virhe: Tämän komennon voi suorittaa vain "; err << "perusmoodissa." << endl; return false; } // Tankkausta ei voi tehdä jos hermoja kuluisi sen seurauksena. if (siirto.tyyppi == TANKKAA && kola_ < siirto.maara) { err << "Virhe: Liian vähän kolaa :'(." << endl; return false; } return true; } // Tulostaa hakkerin tiedot TIEDOT-komentoa varten. void Hakkeri::tulostaTiedot(std::ostream &out) const { out << nimi_ << endl; out << "Moodi: " << MOODIKUVAUKSET[tila_] << endl; if (tila_ == REITITYS || tila_ == PUSKUROINTI) { out << "Taso: " << maara_ << endl; } if (tila_ != OFFLINE) { out << "Hermot: " << hermot_ << "/" << maxhermot_ << endl; out << "Kola: " << kola_ << "/" << maxkola_ << endl; } if (virustaso_ != 0) { out << "Virus: tason " << virustaso_ << " virus." << endl; } if (tila_ == REITITYS) { out << "Kohteet: "; for (unsigned int i = 0; i < reitityskohteet_.size(); i++) { if (i > 0) { out << ", "; } out << reitityskohteet_.at(i)->haeNimi(); } out << endl; } } // Tulostaa tietorivin TILANNE-komentoa varten. void Hakkeri::tulostaTilanne(std::ostream &out) const { out << nimi_; if (tila_ != OFFLINE) { out << " " << hermot_ << "/" << maxhermot_; out << " " << kola_ << "/" << maxkola_; } out << " " << MOODIKUVAUKSET[tila_] << endl; } // Kuluttaa annetun määrän hakkerin hermoista. bool Hakkeri::kulutaHermoja(int maara, std::ostream &out) { out << nimi_ << " menettää hermojaan " << maara << " pisteen verran!"; out << endl; hermot_ -= maara; // Riittivätkö hermot? if (hermot_ > 0) { return true; } else { out << nimi_ << " menettää hermonsa ja lähtee terassille." << endl; vaihdaTila(OFFLINE); return false; } } // Kuluttaa annetun määrän kolaa. bool Hakkeri::kulutaKolaa(int maara, std::ostream &out) { kola_ -= maara; if (kola_ < 0) { // Kulutetaan ylimennyt osa hermoista. int jaljella = -kola_; kola_ = 0; return kulutaHermoja(jaljella, out); } else { // Kola riitti. return true; } } // Vaihtaa tilaa ja nollaa tilaan liittyvät jäsenmuuttujat. void Hakkeri::vaihdaTila(Hakkeritila uusitila) { tila_ = uusitila; virustaso_ = 0; reitityskohteet_.clear(); reititysvuoro_ = 0; maara_ = 0; }