diff options
Diffstat (limited to 'src/scalevalapokalypsi/Model/Adventure.scala')
-rw-r--r-- | src/scalevalapokalypsi/Model/Adventure.scala | 310 |
1 files changed, 278 insertions, 32 deletions
diff --git a/src/scalevalapokalypsi/Model/Adventure.scala b/src/scalevalapokalypsi/Model/Adventure.scala index b10f7d9..dd55727 100644 --- a/src/scalevalapokalypsi/Model/Adventure.scala +++ b/src/scalevalapokalypsi/Model/Adventure.scala @@ -1,8 +1,17 @@ package scalevalapokalypsi.Model import scala.collection.mutable.Map +import scala.collection.immutable import scalevalapokalypsi.Model.Entities.* import scalevalapokalypsi.Model.Entities.NPCs.* +import scala.math.min + + +// This file is different from other files in that this file needs to have lots +// of long lines of text. Thus I've chosen to take the liberty to write +// carelessly lines longer than 80 characters, which is not allowed in other +// files (obviously excluding long strings that will be printed, because +// splitting them apart in the file would make it a pain to grep for them.) /** The class `Adventure` holds data of the game world and provides methods * for implementing a user interface for it. @@ -15,35 +24,147 @@ import scalevalapokalypsi.Model.Entities.NPCs.* */ class Adventure(val playerNames: Vector[String]): - private val middle = Area("Forest", "Olet keskellä metsää. Metsä on täynnä puita.\nLintua laulaa.") - private val northForest = Area("Forest", "Olet keskellä metsää. Tiheä pensaikko estää sinua kulkemasta pohjoiseen. \nLintua laulaa.") - private val southForest = Area("Forest", "The forest just goes on and on.") - private val clearing = Area("Forest Clearing", "You are at a small clearing in the middle of forest.\nNearly invisible, twisted paths lead in many directions.") - private val tangle = Area("Tangle of Bushes", "You are in a dense tangle of bushes. It's hard to see exactly where you're going.") - private val home = Area("Home", "Home sweet home! Now the only thing you need is a working remote control.") - - middle.setNeighbors(Vector("north" -> northForest, "east" -> tangle, "south" -> southForest, "west" -> clearing)) - northForest.setNeighbors(Vector("east" -> tangle, "south" -> middle, "west" -> clearing)) - southForest.setNeighbors(Vector("north" -> middle, "east" -> tangle, "south" -> southForest, "west" -> clearing)) - clearing.setNeighbors(Vector("north" -> northForest, "east" -> middle, "south" -> southForest, "west" -> northForest)) - tangle.setNeighbors(Vector("north" -> northForest, "east" -> home, "south" -> southForest, "west" -> northForest)) - home.setNeighbors(Vector("west" -> tangle)) - - clearing.addItem(Item("battery", "It's a small battery cell. Looks new.", 1)) - southForest.addItem(Item( - "laulukäärö", - "Jukranpujut, löysit laulukäärön!\n" + - "Et vielä voi tehdä sillä mitään, koska et edes osaa laula.", 1 - )) + private val chieftainsGates = Area( + "Kyläpäällikön portti", + "Olet kyläpäällikön talon porttien edessä. Kylänraitti jatkuu pohjoiseen." + ) + private val villageMain = Area( + "Kylänraitti", + "Olet kylänraitilla. Monet kylän asukkaista ovat liikkeellä." + ) + private val bar = Area( + "Baari", + "[TODO] Olet baarissa. Tavallisesti täällä soisi musiikki ja ihmiset tanssivat ilosta, mutta nyt täällä nuokkuu vain muutama ihmistä baaritiskillä." + ) + private val villageNorth = Area( + "Kylän pohjoinen portti", + "Olet kylän pohjoisen sisäänkäynnin ulkopuolella. Luukallio siintää idässä. Kylästänne vie tie naapurikylää kohti pohjoiseen. Lännessä virtaa Kattojoki, jonka anneista kylänne kalastajat saavat elantonsa. Heillä onkin ollut töitä viime aikoina, kun metsästäjät ovat olleet vastahakoisia lähtemään Luumetsään." + ) + private val robberRoad = Area( + "Tie naapurikylään", + "Kuljet tietä naapurikylän suuntaan. Yhtäkkiä rosvojoukko yllättää sinut." + ) + private val villageEast = Area( + "Itäinen pelto", + "Olet pellolla. Näet idässä Luukalliota ympäröivän, synkän näköisen Luumetsän. Voit vannoa näkeväsi siellä epämääräistä liikettä." + ) + private val westForest = Area( + "Luumetsä", + "Olet metsässä Luukallion länsipuolella. Kuulet ympäriltäsi epämääräisiä ääniä, eivätkä ne kaikki ole eläinten aiheuttamia." + ) + private val northForest = Area( + "Luumetsä", + "[TODO] Olet metsässä Luukallion pohjoispuolella. Kuulet ympäriltäsi epämääräisiä ääniä." + ) + private val northOfNorthForest = Area( + "Luumetsä", + "Luumetsä jatkuu jatkumistaan..." + ) + private val eastOfEastForest = Area( + "Luumetsä", + "Luumetsä jatkuu jatkumistaan..." + ) + private val southOfSouthForest = Area( + "Luumetsä", + "Luumetsä jatkuu jatkumistaan..." + ) + private val eastForest = Area( + "Luumetsä", + "[TODO] idk mitä täällä on?" + ) + private val southForest = Area( + "Luumetsä", + "Olet Luukallion eteläpuolella. Näet kallion seinällä sileän kohdan, johon on kirjoitettu riimuja, joita et tunnista. Seinää katsomassa seisoo yksi kyläläisistä, jotka koottiin etsimään teitä piinaavan ilmiön alkulähdettä." + ) + private val villageSouth = Area( + "Eteläinen pelto", + "Olet pellolla kylän eteläpuolella. Näet pellon laidalla pienen metsäaukion. Joki virtaa länsipuolellasi." + ) + private val forestInSouthField = Area( + "Metsäaukio", + "Olet pienellä metsäaukiolla. Näet puiden lomassa pienen majan, josta nousee savua." + ) + private val hutInFieldForest = Area( + "Erakon tupa", + "Olet pimeässä majassa, jonka ilmassa hiki ja yrtinkatku sekoittuvat." + ) + private val caveDescent = Area( + "Käytävä kallion uumeniin", + "Olet hämärässä, soihduin valaistussa käytävässä. Se näyttää vievän syvälle kallion uumeniin. Katosta tippuu hiljalleen jotakin punaista nestettä." + ) + private val secondCaveDescent = Area( + "Käytävä kallion uumeniin", + "Olet käytävässä, joka vie maan pinnalta syvälle kallion uumeniin. Käytävä on tässä kohtaa hieman laajempi." + ) + private val bossDoor = Area( + "Vuoren aula", + "Tunnet kallion painostavan kivimassan päälläsi. Olet puolikaaren muotoisessa huoneessa. Edessäsi on avainreiällinen ovi." + ) + private val storageRoom = Area( + "Varastohuone", + "Olet varastohuoneessa. Näet täällä tynnyreitä, joiden sisältö ei näytä siltä, että tahdot koskea siihen. Tavarat huoneessa näyttävät siltä, että niitä saatettaisiin käyttää joihinkin kulttimenoihin. Luulet, että yksi tynnyreistä on täynnä verta." + ) + private val otherCaveRoom = Area( + "Idk", + "[TODO] mitä tänne?" + ) + private val bossFightRoom = Area( + "Suuri huone kallion sisässä", + "Olet suuressa, ympyränmuotoisessa huoneessa. Lattialle on piirretty verinen kuvio, ja soihdut lepattavat punaista tulta." + ) + private val mountaintop = Area( + "Kalliolla kukkulalla", + "Olet kiivennyt Luukallion huipulle. Näet täältä kotikyläsi peukun kokoisena. Takanasi levittyy Luumetsä pitkänä ja pimeänä, mutta taivaalla valkoiset pilvet halkovat horisonttia. Rinteet ovat kaikkiin suuntiin jyrkkiä paitsi länteen." + ) + private val chieftainsGarden = Area( + "Kyläpäällikön piha", + "Olet kyläpäällikön pihalla. Sinun ei todellakaan pitäisi olla täällä ilman lupaa." + ) + private val chieftainsHouse = Area( + "Kylänpäällikön talo", + "Olet suuressa aulassa kyläpäällikön talossa." + ) + + + chieftainsGates .setNeighbors(Vector("pohjoiseen" -> villageMain)) + villageMain .setNeighbors(Vector("etelään" -> chieftainsGates, "baariin" -> bar, "pohjoiseen" -> villageNorth)) + bar .setNeighbors(Vector("ulos" -> villageMain)) + villageNorth .setNeighbors(Vector("etelään" -> villageMain, "pohjoiseen" -> robberRoad, "itään" -> villageEast)) + robberRoad .setNeighbors(Vector("etelään" -> villageNorth, "pohjoiseen" -> robberRoad)) + villageEast .setNeighbors(Vector("pohjoiseen" -> villageNorth, "etelään" -> villageSouth, "itään" -> westForest)) + villageSouth .setNeighbors(Vector("pohjoiseen" -> villageEast, "itään" -> villageEast, "metsikköön" -> forestInSouthField)) + forestInSouthField.setNeighbors(Vector("mökkiin" -> hutInFieldForest, "pois metsiköstä" -> villageSouth)) + hutInFieldForest .setNeighbors(Vector("ulos" -> forestInSouthField)) + mountaintop .setNeighbors(Vector("länteen" -> westForest)) + northForest .setNeighbors(Vector("pohjoiseen" -> northOfNorthForest, "itään" -> eastForest, "länteen" -> westForest)) + eastForest .setNeighbors(Vector("pohjoiseen" -> northForest, "etelään" -> southForest, "itään" -> eastOfEastForest)) + southForest .setNeighbors(Vector("itään" -> eastForest, "länteen" -> westForest, "etelään" -> southOfSouthForest)) + westForest .setNeighbors(Vector("pohjoiseen" -> northForest, "etelään" -> southForest, "länteen" -> villageEast, "itään" -> mountaintop)) + northOfNorthForest.setNeighbors(Vector("pohjoiseen" -> northOfNorthForest, "itään" -> northOfNorthForest, "länteen" -> northOfNorthForest, "etelään" -> northForest)) + eastOfEastForest .setNeighbors(Vector("pohjoiseen" -> eastOfEastForest, "itään" -> eastOfEastForest, "länteen" -> eastForest, "etelään" -> eastOfEastForest)) + southOfSouthForest.setNeighbors(Vector("pohjoiseen" -> southForest, "itään" -> southOfSouthForest, "länteen" -> southOfSouthForest, "etelään" -> southOfSouthForest)) + caveDescent .setNeighbors(Vector("ulos" -> southForest, "syvemmälle" -> secondCaveDescent)) + secondCaveDescent .setNeighbors(Vector("ylemmäs" -> caveDescent, "syvemmälle" -> bossDoor)) + bossDoor .setNeighbors(Vector("länteen" -> storageRoom, "itään" -> otherCaveRoom, "ulos" -> secondCaveDescent)) + storageRoom .setNeighbors(Vector("ulos" -> bossDoor)) + otherCaveRoom .setNeighbors(Vector("ulos" -> bossDoor)) + chieftainsGarden .setNeighbors(Vector("pohjoiseen" -> chieftainsGates, "kyläpäällikön taloon" -> chieftainsHouse)) + chieftainsHouse .setNeighbors(Vector("ulos" -> chieftainsGarden)) + + chieftainsHouse.addItem(Item("siivilä", "mystinen, musta esine, jonka pohjassa on reikiä ja jota koristaa yliviivattua silmää kuvastava logo", 1)) + val entities: Map[String, Entity] = Map() + val players: Map[String, Player] = Map() + playerNames.foreach(this.addPlayer(_)) + val npcs: Map[String, NPC] = Map() private val zombieAttrs = Vector( - ("Weary zombie", clearing, 20), - ("Smelly zombie", home, 20), - ("Rotten zombie", tangle, 10) + ("mädäntyvä kyläläinen rääsyissä", westForest, 20), + ("mädäntyvä kyläläinen mekossa", westForest, 20), + ("räsyinen olento Joukon vaatteissa", northOfNorthForest, 10) ) zombieAttrs.foreach(z => val zombie = Zombie(this, z(0), z(1), z(2)) @@ -51,15 +172,140 @@ class Adventure(val playerNames: Vector[String]): z(1).addEntity(zombie) ) - def takeNpcTurns(): Unit = - npcs.values.foreach(_.act()) + object JoukosDad extends NPC(this, "Joukon isä", bar, 100, 100): + def act(): Unit = () + private var hasBeenTalkedTo: Boolean = false + def getDialog: String = + if northForest.getEntity( + "räsyinen olento Joukon vaatteissa" + ).isDefined || !hasBeenTalkedTo then + hasBeenTalkedTo = true + "Voi minun poikaani! Mikä karmea kohtalo! Löytäisitkö hänet vallanneen olennon vuorilta? Päästäisitkö poikani kärsimyksestä?" + else + "Ai se on tehty? Voi sentään. No, nyt hän ainakin on saavuttanut levon. Kunpa näin ei olisi tarvinnut käydä." + end JoukosDad - private val gruu = Entity(this, "Gruu", northForest) - northForest.addEntity(gruu) - this.entities += gruu.name -> gruu + object VillageChieftainGuard extends NPC(this, "Vartija", chieftainsGates, 100, 100): + private var isAsleep = false + def act(): Unit = + if this.location.getItemNames.exists(_ == "oluttuoppi") then + this.location.observeEvent(this.pickUp("oluttuoppi")) + this.location.observeEvent(Event(immutable.Map.empty, s"${this.name} juo oluen ja sammuu.")) + this.isAsleep = true + this.location.setNeighbor("etelään", chieftainsGarden) + def getDialog: String = + if !this.isAsleep then + "Et voi mennä kyläpäällikön taloon ilman kutsua." + else + "ZzzzZzZZZz..." + end VillageChieftainGuard - val players: Map[String, Player] = Map() - playerNames.foreach(this.addPlayer(_)) + + object Bartender extends NPC(this, "baarin pitäjä", bar, 100, 100): + + private var dialogIndex = 0 + private val dialogs = Vector( + "Onnea matkaan. Tarjoan sinulle tuopin olutta rohkaisuksi.", + "Onnea matkaan." + ) + + def act(): Unit = () + + def getDialog: String = + if dialogIndex == 0 then + this.location.addItem(Item( + "oluttuoppi", + "Tuopillinen kuohuvaa ja raikasta olutta. Se tuoksuu aika vahvalta.", + 1 + )) + this.location.observeEvent( + Event( + immutable.Map.empty, + "Baarimikko kaataa tuoppiin olutta ja asettaa oluttuopin pöydälle." + ) + ) + dialogIndex = min(dialogIndex + 1, this.dialogs.length) + dialogs(dialogIndex - 1) + end getDialog + + end Bartender + + //object Hermit extends NPC(this, "Tietäjäerakko", hutInFieldForest, 100, 100): + // + // private var scrollRecipients = + +// object ShoutingCultist extends Cultist(this, "Kaapupäinen henkilö", secondCaveDescent, 100, 100): +// private var hasShouted = false +// override def act(): Unit = +// val playerLocations = players.values.map(_.location) +// if !hasShouted && playerLocations contains caveDescent then +// caveDescent.observe(Event(immutable.Map.empty, "Kuulet huudon: “Tunkeilija! Valmistautukaa!”")) +// hasShouted = true +// super.act() +// end ShoutingCultist +// val cultist2 = Cultist(this, "Silmätön kaljupää", secondCaveDescent) + + this.npcs += Bartender.name -> Bartender + this.bar.addEntity(Bartender) + this.npcs += JoukosDad.name -> JoukosDad + this.bar.addEntity(JoukosDad) + this.npcs += VillageChieftainGuard.name -> VillageChieftainGuard + this.chieftainsGates.addEntity(VillageChieftainGuard) +// this.npcs += ShoutingCultist.name -> ShoutingCultist +// this.secondCaveDescent.addEntity(ShoutingCultist) +// this.npcs += cultist2 +// this.secondCaveDescent.addEntity(cultist2) + + + object SeparatorScroll extends Item( + "separoitumisen laulukäärö", + "Laulukäärö, joka antaa sanat separoitumisen laululle, joka saa aikaan raon jopa harmaaseen kiveen.", + 1 + ): + + class SeparatorEffect(actor: Entity) extends SingEffect(actor): + def getVerses: Vector[String] = + Vector( + "Separoidu kova kivi", + "jakaudu ja ratkeapi", + "laske minut syvyyksiisi", + "kalmankylmiin lähteisiisi" + ) + + def apply(quality: Float): Event = + if actor.location == southForest && quality > .1 && !southForest.hasNeighbor("kallion sisään") then + southForest.setNeighbor("kallion sisään", caveDescent) + Event( + Vector(actor -> "Kivi halkeaa rytinällä. Nyt näet sisään soihduilla valaistuun käytävään, joka johtaa kallion uumeniin.").toMap, + s"Näet kun kivi halkeaa kahtia henkilön ${actor.name} laulun voimasta. Kallion sisästä paljastuu käytävä." + ) + else if actor.location == southForest && quality <= .1 then + Event( + Vector(actor -> "Kivi natisee liitoksissaan, mutta jää odottamaan voimallisempaa laulua.").toMap, + s"Kivi natisee hieman kun ${actor.name} laulaa, mutta mitään merkittävää ei tapahdu." + ) + else + Event(Vector(actor -> "Laulat laulun, mutta mitään ei tapahdu.").toMap, "") + end SeparatorEffect + + override def use(user: Entity): Option[Event] = + user match + case p: Player => + p.setSingEffect(SeparatorEffect(p)) + Some(Event( + Vector(user -> "Avaat käärön varovasti ja aloitat separoitumisen laulun.").toMap, + s"${user.name} alkaa laulamaan kääröstä." + )) + case other => + None + end use + + end SeparatorScroll + + bar.addItem(SeparatorScroll) + + def takeNpcTurns(): Unit = + npcs.values.foreach(_.act()) /** Adds a player entity with the specified name to the game. * @@ -67,8 +313,8 @@ class Adventure(val playerNames: Vector[String]): * @return the created player entity */ def addPlayer(name: String): Player = - val newPlayer = Player(this, name, middle) - middle.addEntity(newPlayer) + val newPlayer = Player(this, name, chieftainsGates) + chieftainsGates.addEntity(newPlayer) this.entities += name -> newPlayer players += name -> newPlayer newPlayer |