diff options
author | Joel Kronqvist <joel.kronqvist@iki.fi> | 2024-11-27 12:29:43 +0200 |
---|---|---|
committer | Joel Kronqvist <joel.kronqvist@iki.fi> | 2024-11-27 12:29:43 +0200 |
commit | 98407b35ff477f372baa92bf582b90a961d4ad16 (patch) | |
tree | bb58925090075d1e9e30dd1593547db2cbe03bb6 /src/scalevalapokalypsi/Model/Entities | |
parent | 38900e0b291d5e0f59afaaa239cd237f733b6588 (diff) | |
download | scalevalapokalypsi-98407b35ff477f372baa92bf582b90a961d4ad16.tar.gz scalevalapokalypsi-98407b35ff477f372baa92bf582b90a961d4ad16.zip |
Added part of story & improved singing with multiple verses & hemingway distance
Diffstat (limited to 'src/scalevalapokalypsi/Model/Entities')
7 files changed, 317 insertions, 92 deletions
diff --git a/src/scalevalapokalypsi/Model/Entities/Entity.scala b/src/scalevalapokalypsi/Model/Entities/Entity.scala index aa2a2e2..6a2072d 100644 --- a/src/scalevalapokalypsi/Model/Entities/Entity.scala +++ b/src/scalevalapokalypsi/Model/Entities/Entity.scala @@ -30,7 +30,8 @@ class Entity( * * @return the verse to sing against this entity */ - def getVerseAgainst: String = "Esimerkkirivi laulettavaksi" + def getVerseAgainst: Vector[String] = + Vector("Esimerkkirivi laulettavaksi") def isAlive = this.hp > 0 @@ -42,7 +43,7 @@ class Entity( this.condition(1) ) else - println(s"Could remove myself: ${this.adventure.removeEntity(this.name)}") + this.adventure.removeEntity(this.name) Event( Vector(this -> "Olet täysin menettänyt toimintakykysi. Kaadut elottomana maahan." @@ -97,9 +98,9 @@ class Entity( val leaving = oldEntities.zip( Vector.fill (oldEntities.size) - (s"${this.name} leaves this location.") + (s"${this.name} lähtee $direction") ) - val self = Vector((this, s"You go $direction.")) + val self = Vector((this, s"Menet $direction.")) Some(Event( (leaving ++ self).toMap, s"$name saapuu tänne." @@ -112,8 +113,12 @@ class Entity( val inventoryWeight = items.values.map(p => p(1).weight).sum if inventoryWeight + i.weight > maxInventoryWeight then Event( - immutable.Map.from(Vector((this, s"Voimasi eivät riitä kannattelemaan esinettä ${i.name}, koska kannat liikaa"))), - s"") + Vector(( + this, + s"Voimasi eivät riitä kannattelemaan esinettä ${i.name}, koska kannat liikaa" + )).toMap, + s"" + ) else if items.contains(i.name) then val (current, _) = items(i.name) @@ -121,13 +126,27 @@ class Entity( else this.items += i.name -> (1, i) Event( - immutable.Map.from(Vector((this, s"Poimit esineen ${i.name}"))), + Vector((this, s"Poimit esineen ${i.name}")).toMap, s"$name poimi esineen ${i.name}" ) - case None => Event( - immutable.Map.from(Vector((this, s"Täällä ei ole esinettä $itemName noukittavaksi."))), - s"${this.name} yritti ottaa jotakin, mutta sai vain likaa käsilleen." - ) + case None => + Event( + immutable.Map.from(Vector(( + this, + s"Täällä ei ole esinettä $itemName noukittavaksi." + ))), + s"${this.name} yritti ottaa jotakin, mutta sai vain likaa käsilleen." + ) + + def removeItem(itemName: String): Boolean = + this.items.get(itemName).map((count, item) => + if count > 1 then + this.items.remove(itemName) + else + this.items(itemName) = (count - 1, item) + assert(this.items(itemName)(0) == count - 1) + Some(true) + ).isDefined def drop(itemName: String): Event = this.items.remove(itemName) match @@ -138,12 +157,21 @@ class Entity( this.items += itemName -> (current - 1, item) this.currentLocation.addItem(item) Event( - immutable.Map.from(Vector((this, s"Pudotit esineen $itemName"))), + immutable.Map.from( + Vector((this, s"Pudotit esineen $itemName")) + ), s"$name Pudotti esineen $itemName" ) + case Some((current, item)) => + this.items.remove(item.name) + println(" [virhe] esineitä ei koskaan pitäisi olla nollaa") + Event( + Vector((this, "Sinulla ei ole tuota esinettä.")).toMap, + "" + ) case None => Event( - immutable.Map.from(Vector((this, "Sinulla ei ole tätä esinettä!"))), - s"$name yritti tonkia rpustaan esineen $itemName mutta ei löytänyt sitä." + Vector((this, "Sinulla ei ole tätä esinettä!")).toMap, + s"$name yritti tonkia repustaan esineen $itemName mutta ei löytänyt sitä." ) def sayTo(entity: Entity, message: String): Event = @@ -154,7 +182,7 @@ class Entity( (this, s"Sanot niin henkilölle ${entity.name}."), (entity, s"${this.name}: “${message}”") )), - s"Kuulet henkilön ${this.name} sanovan jotain henkilölle ${entity.name}" + s"Kuulet henkilön ${this.name} sanovan jotain henkilölle ${entity.name}." ) def ponder(message: String): Event = @@ -185,7 +213,14 @@ class Entity( * @param itemName the name to check * @return whether this entity has this item and can drop it */ - def canDrop(itemName: String): Boolean = this.items.contains(itemName) + //def canDrop(itemName: String): Boolean = this.items.contains(itemName) + + def useItem(itemName: String): Event = + val item: Option[Item] = this.items.get(itemName).map(_(1)) + val event: Option[Event] = item.flatMap(_.use(this)) + event.getOrElse( + Event(Vector(this -> "Sinulla ei ole tuota esinettä.").toMap, "") + ) /** Returns a brief description of the player’s state, for debugging purposes. */ override def toString = s"${this.name} at ${this.location.name}" @@ -204,7 +239,4 @@ class Entity( s"") - - - end Entity diff --git a/src/scalevalapokalypsi/Model/Entities/NPCs/Bartender.scala b/src/scalevalapokalypsi/Model/Entities/NPCs/Bartender.scala new file mode 100644 index 0000000..1743380 --- /dev/null +++ b/src/scalevalapokalypsi/Model/Entities/NPCs/Bartender.scala @@ -0,0 +1,52 @@ +/* +package scalevalapokalypsi.Model.Entities.NPCs + +import scalevalapokalypsi.Model.{Area,Event,Item,Adventure} +import scala.math.min + +class Bartender( + adventure: Adventure, + initialLocation: Area +) extends NPC( + adventure, + "baarimikko", + initialLocation, + 100, + 100 +): + + + private var dialogIndex = 0 + + private val dialogs = Vector( + "Onnea matkaan. Tarjoan sinulle tuopin olutta rohkaisuksi.", + "Onnea matkaan." + ) + + 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( + Map.empty, + "Baarimikko kaataa tuoppiin olutta ja asettaa oluttuopin pöydälle." + ) + ) + + dialogIndex = min(dialogIndex + 1, this.dialogs.length) + + dialogs(dialogIndex - 1) + + end getDialog + + + def act(): Unit = () + + +end Bartender +*/ diff --git a/src/scalevalapokalypsi/Model/Entities/NPCs/Cultist.scala b/src/scalevalapokalypsi/Model/Entities/NPCs/Cultist.scala new file mode 100644 index 0000000..fa5602e --- /dev/null +++ b/src/scalevalapokalypsi/Model/Entities/NPCs/Cultist.scala @@ -0,0 +1,53 @@ + +package scalevalapokalypsi.Model.Entities.NPCs + +import scala.collection.mutable.Buffer +import scalevalapokalypsi.Model.* +import scalevalapokalypsi.Model.Entities.* +import scala.util.Random + +class Cultist( + adventure: Adventure, + identifier: String, + initialLocation: Area, + initialHP: Int = 100, + maxHP: Int = 100 +) extends NPC(adventure, identifier, initialLocation, initialHP, maxHP): + + private val damage = 20 + + override def getDialog: String = + "Verta! Lisää verta!" + + override def act(): Unit = + val possibleVictims = this.location + .getEntities + .filter(_ != this) + .filter(_ match + case c: Cultist => false + case other => true + ) + .toVector + val index: Int = + if possibleVictims.isEmpty then 0 + else Random.between(0, possibleVictims.length) + if !possibleVictims.isEmpty then + this.location.observeEvent( + this.curse(possibleVictims(index)) + ) + + + private def curse(entity: Entity): Event = + entity.takeDamage(this.damage) + Event( + Map.from(Vector(( + entity, + s"${this.name} lausuu pimeän loitsun. Näet varjon pyyhältävän sinua kohti ja sinut valtaa kylmyys.\n" + + s"${entity.condition(0)}" + ))), + s"${this.name} käyttää kirousta henkilöön ${entity.name}\n" + + s"${entity.condition(1)}" + ) + +end Cultist + diff --git a/src/scalevalapokalypsi/Model/Entities/NPCs/NPC.scala b/src/scalevalapokalypsi/Model/Entities/NPCs/NPC.scala index 944f2e6..7d9996c 100644 --- a/src/scalevalapokalypsi/Model/Entities/NPCs/NPC.scala +++ b/src/scalevalapokalypsi/Model/Entities/NPCs/NPC.scala @@ -1,10 +1,8 @@ package scalevalapokalypsi.Model.Entities.NPCs -import scala.collection.mutable.Buffer import scalevalapokalypsi.Model.* import scalevalapokalypsi.Model.Entities.* -import scala.util.Random /** A `NPC` object represents a non-playable in-game character controlled by * the server using this objects `act` method. It can also be "talked to": it @@ -25,67 +23,3 @@ abstract class NPC( ) extends Entity(adventure, name, initialLocation, initialHP, maxHp): def getDialog: String def act(): Unit - -class Zombie( - adventure: Adventure, - identifier: String, - initialLocation: Area, - initialHP: Int = 20 -) extends NPC(adventure, identifier, initialLocation, initialHP, 20): - - private val damage = 10 - private val dialogs = Vector( - "örvlg", - "grr", - "äyyrrrgrlgb ww", - "aaak brzzzwff ååö", - "äkb glan abglum", - "öub gpa" - ) - - override def getDialog: String = - val dialogIndex = Random.between(0, this.dialogs.length) - this.dialogs(dialogIndex) - - override def act(): Unit = - val possibleVictims = this.location - .getEntities - .filter(_ != this) - .toVector - val index: Int = - if possibleVictims.isEmpty then 0 - else Random.between(0, possibleVictims.length) - if possibleVictims.isEmpty then - val possibleDirections = this.location.getNeighborNames.toVector - val directionIndex = Random.between(0, possibleDirections.length*2) - possibleDirections - .toVector - .lift(directionIndex) - .flatMap(this.go(_)) - .foreach(this.location.observeEvent(_)) - else - this.location.observeEvent( - this.attack(possibleVictims(index)) - ) - - - private def attack(entity: Entity): Event = - if Random.nextBoolean() then - entity.takeDamage(this.damage) - Event( - Map.from(Vector(( - entity, - s"${this.name} puree sinua, hyi yäk!\n" + - s"${entity.condition(0)}" - ))), - s"${this.name} puree henkilöä ${entity.name}.\n" + - s"${entity.condition(1)}" - ) - else - Event( - Map.from(Vector(( - entity, - s"${this.name} yrittää purra sinua mutta kaatuu ohitsesi." - ))), - s"${this.name} yrittää purra henkilöä ${entity.name}, mutta epäonnistuu surkeasti." - ) diff --git a/src/scalevalapokalypsi/Model/Entities/NPCs/Robber.scala b/src/scalevalapokalypsi/Model/Entities/NPCs/Robber.scala new file mode 100644 index 0000000..fc009a6 --- /dev/null +++ b/src/scalevalapokalypsi/Model/Entities/NPCs/Robber.scala @@ -0,0 +1,72 @@ + +package scalevalapokalypsi.Model.Entities.NPCs + +import scala.collection.mutable.Buffer +import scalevalapokalypsi.Model.* +import scalevalapokalypsi.Model.Entities.* +import scala.util.Random + +class Robber( + adventure: Adventure, + name: String, + val weaponName: String, + val weaponDamage: Int, + val hitChance: Float, + initialLocation: Area, + initialHP: Int = 20 +) extends NPC(adventure, name, initialLocation, initialHP, 20): + + private val dialogs = Vector( + "Rahat tai henki!", + "Anna tänne!", + "Syödään se ryöstön jälkeen!", + "Vesihiisi sihisi hississä ja muumit laaksosta poissaolollaan." + ) + + override def getDialog: String = + val dialogIndex = Random.between(0, this.dialogs.length) + this.dialogs(dialogIndex) + + override def act(): Unit = + val possibleVictims = this.location + .getEntities + .filter(_ != this) + .filter(_ match + case z: Robber => false + case other => true + ) + .toVector + val index: Int = + if possibleVictims.isEmpty then 0 + else Random.between(0, possibleVictims.length) + if !possibleVictims.isEmpty then + this.location.observeEvent( + this.attack(possibleVictims(index)) + ) + //else + // this.location.getNeighborNames.filter(this.location.neighbor(_).map(_.getEntities.size > 0).getOrElse(false)) + + + private def attack(entity: Entity): Event = + if Random.nextFloat() < this.hitChance then + entity.takeDamage(this.weaponDamage) + Event( + Map.from(Vector(( + entity, + s"${this.name} lyö sinua ${this.weaponName}\n" + + s"${entity.condition(0)}" + ))), + s"${this.name} lyö henkilöä ${entity.name} ${this.weaponName}.\n" + + s"${entity.condition(1)}" + ) + else + Event( + Map.from(Vector(( + entity, + s"${this.name} yrittää lyödä sinua mutta väistät." + ))), + s"${this.name} yrittää lyödä henkilöä ${entity.name}, mutta tämä väistää." + ) + +end Robber + diff --git a/src/scalevalapokalypsi/Model/Entities/NPCs/Zombie.scala b/src/scalevalapokalypsi/Model/Entities/NPCs/Zombie.scala new file mode 100644 index 0000000..56cb160 --- /dev/null +++ b/src/scalevalapokalypsi/Model/Entities/NPCs/Zombie.scala @@ -0,0 +1,70 @@ + +package scalevalapokalypsi.Model.Entities.NPCs + +import scala.collection.mutable.Buffer +import scalevalapokalypsi.Model.* +import scalevalapokalypsi.Model.Entities.* +import scala.util.Random + +class Zombie( + adventure: Adventure, + identifier: String, + initialLocation: Area, + initialHP: Int = 20 +) extends NPC(adventure, identifier, initialLocation, initialHP, 20): + + private val damage = 10 + private val dialogs = Vector( + "örvlg", + "grr", + "äyyrrrgrlgb ww", + "aaak brzzzwff ååö", + "äkb glan abglum", + "öub gpa" + ) + + override def getDialog: String = + val dialogIndex = Random.between(0, this.dialogs.length) + this.dialogs(dialogIndex) + + override def act(): Unit = + val possibleVictims = this.location + .getEntities + .filter(_ != this) + .filter(_ match + case z: Zombie => false + case other => true + ) + .toVector + val index: Int = + if possibleVictims.isEmpty then 0 + else Random.between(0, possibleVictims.length) + if !possibleVictims.isEmpty then + this.location.observeEvent( + this.attack(possibleVictims(index)) + ) + + + private def attack(entity: Entity): Event = + if Random.nextBoolean() then + entity.takeDamage(this.damage) + Event( + Map.from(Vector(( + entity, + s"${this.name} puree sinua, hyi yäk!\n" + + s"${entity.condition(0)}" + ))), + s"${this.name} puree henkilöä ${entity.name}.\n" + + s"${entity.condition(1)}" + ) + else + Event( + Map.from(Vector(( + entity, + s"${this.name} yrittää purra sinua mutta kaatuu ohitsesi." + ))), + s"${this.name} yrittää purra henkilöä ${entity.name}, mutta epäonnistuu surkeasti." + ) + +end Zombie + diff --git a/src/scalevalapokalypsi/Model/Entities/Player.scala b/src/scalevalapokalypsi/Model/Entities/Player.scala index 9fc929d..62d4180 100644 --- a/src/scalevalapokalypsi/Model/Entities/Player.scala +++ b/src/scalevalapokalypsi/Model/Entities/Player.scala @@ -1,6 +1,7 @@ package scalevalapokalypsi.Model.Entities import scala.collection.mutable.{Buffer, Map} +import scala.collection.immutable import scalevalapokalypsi.Model.* /** A `Player` object represents a player character controlled by one real-life player @@ -21,6 +22,15 @@ class Player( private val observations: Buffer[String] = Buffer.empty private val observedEvents: Buffer[Event] = Buffer.empty private var pendingSingEffect: Option[SingEffect] = None +// private var verseToSing: Option[String] = None + + override def getVerseAgainst: Vector[String] = + Vector( + "Pian pimeässä suossa", + "lepäät levä ympärilläs", + "lauluasi lausumahan", + "et sikaa paremmin pysty" + ) override def observe(event: Event): Unit = this.observedEvents.append(event) @@ -44,8 +54,11 @@ class Player( def setSingEffect(effect: SingEffect): Unit = this.pendingSingEffect = Some(effect) - def getSingEffectTarget: Option[Entity] = - this.pendingSingEffect.map(_.target) + def getVerses: Option[Vector[String]] = + this.pendingSingEffect.map(_.getVerses) + +// def getSingEffectTarget: Option[Entity] = +// this.pendingSingEffect.map(_.target) /** Applies the pending sing effect and informs the surronding Entities * about the effects of the song. @@ -65,12 +78,11 @@ class Player( else ("erinomaista", "merkittävä") val quality = s"Laulu on ${qualityDescriptions(0)} ja sen vaikutus on ${qualityDescriptions(1)}." - val event = Event(Map.empty, s"$quality") + val event = Event(immutable.Map.empty, s"$quality") this.location.observeEvent(event) - this.pendingSingEffect.map(ef => ef(singQuality)) + this.pendingSingEffect + .map(ef => ef(singQuality)) + .map(this.location.observeEvent(_)) this.pendingSingEffect = None - - - end Player |