package scalevalapokalypsi.Model import scalevalapokalypsi.Model.Entities.* import scalevalapokalypsi.Model.Entities.NPCs.* /** 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 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 "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(false -> 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