package scalevalapokalypsi.Model import scalevalapokalypsi.Model.Entities.* import scalevalapokalypsi.Model.Entities.NPCs.* import scala.collection.immutable /** The class `Action` represents actions that a player may take in a text * adventure game. `Action` objects are constructed on the basis of textual * commands and are, in effect, parsers for such commands. An action object is * immutable after creation. * * @param input a textual in-game command such as “go east” or “rest” */ class Action(input: String): private val commandText = input.trim.toLowerCase private val verb = commandText.takeWhile( _ != ' ' ) private val modifiers = commandText.drop(verb.length).trim /** Causes the given player to take the action represented by this object, * assuming that the command was understood. Informs the player and the * entities surrounding it about the result. Returns true if the command * was understood and possible, false otherwise. * * @param actor the acting player * @return Boolean indicating whether the action possibly taken takes a * turn or not. */ def help(actor: Entity): Event = Event( immutable.Map.from(Vector((actor, "Tässä ovat komennot," + " joita voit" + " käyttää pelin aikana:\n\napua/?/help:" + " Näyttää pelaajalle saatavilla olevat" + " komennot ja" + " kertoo mitä ne tekevät.\n\nkäytä [esine]:" + " Käyttää kyseisen esineen." + " Vaikutus vaihtelee esineiden välillä." + "\n\nlaula [olento] suohon: Laulaa toisen" + " olennon suohon.\n\nlepää:" + " Pelaaja levähtää, ei mitään sen" + " erikoisempaa vaikutusta." + "\n\nmene [suunta]: Vaihtaa pelaajan" + " paikkaa/sijaintia pelissä," + " jos se on mahdollista. Komennon perään laitetaan" + " ilmansuunta," + " joka kertoo, mihin suuntaan pelaaja liikkuu." + "\n\npoimi/ota [esine]:" + " Lisää kyseisen esineen pelaajan tavaraluetteloon," + " jos se on saatavilla" + " kyseisessä sijainnissa. Komennon perään kirjoitetaan" + " esineen nimi, mikä halutaan ottaa. \n\npuhu [pelaaja]:" + " Välittää viestin olennolle, joka ei ole pelaaja." + "\n\nsano [olento]: Välittää viestin toiselle" + " pelaajalle.\n\ntavaraluettelo:" + " Näyttää, mitä esineitä pelaajalla on" + " tavaraluettelossaan. Näyttää lisäksi esineiden määrän." + " Jos pelaajalla ei ole esineitä tavaraluettelossaan" + ", niin komento kertoo tavaraluettelon olevan tyhjä." + "\n\ntiputa/pudota [esine]:" + " Pudottaa kyseisen esineen pelaajan tavaraluettelosta," + " jolloin se myös vähennetään pelaajan tavaraluettelosta." + " \n\nxyzzy: Nam nam "))), s"" ) def execute(actor: Player): Boolean = val oldLocation = actor.location val resOption: Option[(Boolean, Event)] = this.verb match case "mene" => val result = actor.go(this.modifiers) result.foreach(r => if actor.location != oldLocation then oldLocation.observeEvent(r) ) result.map((true, _)) case "help" | "?" | "apua" => Some((false, this.help(actor))) case "lepää" => Some((true, actor.rest())) case "poimi" | "ota" => Some((false, actor.pickUp(this.modifiers))) case "tavaraluettelo" => Some((false, actor.inventory)) case "sano" => val entityNames = actor.location.getEntityNames.map(_.toLowerCase) val recipientNamePair = entityNames.flatMap(name => val possibleNamesWithSuffix = (0 to "ille".length).map(i => modifiers.takeRight(name.length + i) ) possibleNamesWithSuffix.find(s => s.take(name.length) == name ) .map(_.splitAt(name.length))).headOption val recipient = recipientNamePair.flatMap(p => actor.location.getEntity(p(0)) ) val message = recipientNamePair .map(p => modifiers.dropRight(p(0).length + p(1).length)) .filter(_.takeRight(1) == " ") .map(_.dropRight(1)) message.map(m => recipient.map(e => (false, actor.sayTo(e, m))) ).getOrElse( Some((false, actor.say(modifiers))) ) case "puhu" => val recipient = modifiers .indices.take("ille".length + 1) .map(i => modifiers.take(modifiers.length - i)) .find(name => actor.location.getEntity(name).isDefined) .flatMap(name => actor.location.getEntity(name)) val dialog = recipient match case Some(npc: NPC) => s"${npc.name}: ”${npc.getDialog}”" case Some(player: Player) => "Et voi puhua pelaajille, vain sanoa asioita heille." case Some(other) => "Et voi puhua tälle olennolle." case None => "Kyseistä puhujaa ei löytynyt." val fromThirdPerson = recipient .filter(a => a.isInstanceOf[NPC]) .map(a => s"${actor.name} puhuu $modifiers") Some( ( false, Event(Vector(( actor, dialog )).toMap, fromThirdPerson.getOrElse("")) ) ) case "tiputa" | "pudota" => Some((false, actor.drop(this.modifiers))) case "käytä" => Some(true -> actor.useItem(this.modifiers)) case "laula" => val end = modifiers.takeRight("suohon".length) val start = modifiers.take(modifiers.length - "suohon".length).trim if end == "suohon" then val targetEntity = actor.location.getEntity(start) targetEntity .foreach(e => actor.setSingEffect(DefaultSingAttack(e))) targetEntity.map(t => (false, Event( Map.from(Vector((t, s"${actor.name} laulaa sinua suohon!"))), s"${actor.name} laulaa henkilöä ${t.name} suohon." )) ) else None case "xyzzy" => Some((false, Event( Map.from(Vector((actor, "Grue maistuu."))), s"${actor.name} maistaa.") )) case other => None val res: (Boolean, Event) = resOption .getOrElse((false, Event( Map.from(Vector((actor, "Tuo ei ole asia, jonka voit tehdä."))), "" ))) actor.location.observeEvent(res(1)) res(0) /** Returns a textual description of the action object, for debugging purposes. */ override def toString = s"$verb (modifiers: $modifiers)" end Action