aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksi Heikkila <aleksi.e.heikkila@aalto.fi>2024-11-27 17:26:16 +0200
committerAleksi Heikkila <aleksi.e.heikkila@aalto.fi>2024-11-27 17:26:16 +0200
commitb50a8e42b6b69ce4e15773c73cf68d2ac8f2175d (patch)
tree14a95bc1fd5ec6cfbfd25f795e46fc389ee6625a
parent34dc64a1387f2904b4c23ac3fcfea35c9670088e (diff)
parent302455bac062080bf197b44e07ed53a3454be4c5 (diff)
downloadscalevalapokalypsi-b50a8e42b6b69ce4e15773c73cf68d2ac8f2175d.tar.gz
scalevalapokalypsi-b50a8e42b6b69ce4e15773c73cf68d2ac8f2175d.zip
help-komento
-rw-r--r--src/scalevalapokalypsi/Model/Action.scala2
-rw-r--r--src/scalevalapokalypsi/Model/Adventure.scala253
-rw-r--r--src/scalevalapokalypsi/Model/Entities/Entity.scala7
-rw-r--r--src/scalevalapokalypsi/Model/Entities/NPCs/Cthulthu.scala48
-rw-r--r--src/scalevalapokalypsi/Model/Entities/NPCs/Cultist.scala13
-rw-r--r--src/scalevalapokalypsi/Model/Entities/NPCs/Miikkulainen.scala33
-rw-r--r--src/scalevalapokalypsi/Model/Entities/NPCs/Tentacle.scala59
-rw-r--r--src/scalevalapokalypsi/Model/Entities/NPCs/Villager.scala79
-rw-r--r--src/scalevalapokalypsi/Model/Entities/NPCs/Zombie.scala6
-rw-r--r--src/scalevalapokalypsi/Server/Client.scala5
-rw-r--r--src/scalevalapokalypsi/Server/Server.scala2
-rw-r--r--src/scalevalapokalypsi/constants/constants.scala2
-rw-r--r--src/scalevalapokalypsi/utils/utils.scala2
13 files changed, 398 insertions, 113 deletions
diff --git a/src/scalevalapokalypsi/Model/Action.scala b/src/scalevalapokalypsi/Model/Action.scala
index 94d13a5..4089b48 100644
--- a/src/scalevalapokalypsi/Model/Action.scala
+++ b/src/scalevalapokalypsi/Model/Action.scala
@@ -134,7 +134,7 @@ class Action(input: String):
)
case "tiputa" | "pudota" => Some((false, actor.drop(this.modifiers)))
case "käytä" =>
- Some(true -> actor.useItem(this.modifiers))
+ Some(false -> actor.useItem(this.modifiers))
case "laula" =>
val end = modifiers.takeRight("suohon".length)
val start =
diff --git a/src/scalevalapokalypsi/Model/Adventure.scala b/src/scalevalapokalypsi/Model/Adventure.scala
index dd55727..9f538c5 100644
--- a/src/scalevalapokalypsi/Model/Adventure.scala
+++ b/src/scalevalapokalypsi/Model/Adventure.scala
@@ -1,6 +1,6 @@
package scalevalapokalypsi.Model
-import scala.collection.mutable.Map
+import scala.collection.mutable.{Map,Buffer}
import scala.collection.immutable
import scalevalapokalypsi.Model.Entities.*
import scalevalapokalypsi.Model.Entities.NPCs.*
@@ -24,6 +24,18 @@ import scala.math.min
*/
class Adventure(val playerNames: Vector[String]):
+ // Structure:
+ // * Area definitions
+ // * Area neighbor definitions
+ // * Item definitions
+ // * Public values for containing entities
+ // * NPC definitions & adding them
+ // * Adding players
+ // * Public methods
+
+
+ // Area definitions
+
private val chieftainsGates = Area(
"Kyläpäällikön portti",
"Olet kyläpäällikön talon porttien edessä. Kylänraitti jatkuu pohjoiseen."
@@ -34,7 +46,7 @@ class Adventure(val playerNames: Vector[String]):
)
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ä."
+ "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",
@@ -54,7 +66,7 @@ class Adventure(val playerNames: Vector[String]):
)
private val northForest = Area(
"Luumetsä",
- "[TODO] Olet metsässä Luukallion pohjoispuolella. Kuulet ympäriltäsi epämääräisiä ääniä."
+ "Olet metsässä Luukallion pohjoispuolella. Kuulet ympäriltäsi epämääräisiä ääniä."
)
private val northOfNorthForest = Area(
"Luumetsä",
@@ -70,7 +82,7 @@ class Adventure(val playerNames: Vector[String]):
)
private val eastForest = Area(
"Luumetsä",
- "[TODO] idk mitä täällä on?"
+ "Olet Luumetsässä. Luukallio kohoaa lännessä."
)
private val southForest = Area(
"Luumetsä",
@@ -105,8 +117,8 @@ class Adventure(val playerNames: Vector[String]):
"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?"
+ "Sellihuone",
+ "Olet huoneessa, joka on täynnä sellejä. Selleihin on lukittu pahoinvoivan näköisiä ihmisiä, joilla on paiseita."
)
private val bossFightRoom = Area(
"Suuri huone kallion sisässä",
@@ -126,6 +138,8 @@ class Adventure(val playerNames: Vector[String]):
)
+ // Area neighbor definitions
+
chieftainsGates .setNeighbors(Vector("pohjoiseen" -> villageMain))
villageMain .setNeighbors(Vector("etelään" -> chieftainsGates, "baariin" -> bar, "pohjoiseen" -> villageNorth))
bar .setNeighbors(Vector("ulos" -> villageMain))
@@ -143,7 +157,7 @@ class Adventure(val playerNames: Vector[String]):
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))
+ caveDescent .setNeighbors(Vector("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))
@@ -154,17 +168,80 @@ class Adventure(val playerNames: Vector[String]):
chieftainsHouse.addItem(Item("siivilä", "mystinen, musta esine, jonka pohjassa on reikiä ja jota koristaa yliviivattua silmää kuvastava logo", 1))
+ // Item definitions
+
+ private val oluttuoppi = Item("oluttuoppi", "Tuopillinen kylmää ja kuohuvaa juomaa. Se tuoksuu aika tujulta.", 1)
+
+ 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)
+ caveDescent.setNeighbor("ulos", southForest)
+ 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
+
+
+ // Public values for containing entities
+
val entities: Map[String, Entity] = Map()
val players: Map[String, Player] = Map()
- playerNames.foreach(this.addPlayer(_))
val npcs: Map[String, NPC] = Map()
+
+ // Adding players
+
+ playerNames.foreach(this.addPlayer(_))
+
+
+ // NPC definitions & adding them
+
private val zombieAttrs = Vector(
("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)
+ ("räsyinen olento Joukon vaatteissa", northOfNorthForest, 10),
+ ("vaappuva paiseinen henkilö", otherCaveRoom, 30),
+ ("epämuodostunut henkilö", otherCaveRoom, 20),
+ ("kädetön olento", otherCaveRoom, 20)
)
zombieAttrs.foreach(z =>
val zombie = Zombie(this, z(0), z(1), z(2))
@@ -200,109 +277,77 @@ class Adventure(val playerNames: Vector[String]):
"ZzzzZzZZZz..."
end VillageChieftainGuard
-
- 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."
+ val bartender = Villager(
+ this,
+ "Baarin pitäjä",
+ bar,
+ Vector(
+ (
+ "Onnea matkaan. Talo tarjoaa tuopin olutta rohkaisuksi.",
+ Some((me: Entity) =>
+ me.location.addItem(oluttuoppi)
+ Event(immutable.Map.empty, "Baarimikko kaataa tuoppiin olutta ja asettaa sen pöydälle.")
+ )
+ ),
+ ("Onnea matkaan", None)
+ )
+ )
+ val hermit = Villager(
+ this,
+ "erakkotietäjä",
+ hutInFieldForest,
+ Vector(
+ "Olen kuullut tuollaisista riimuista. Ota tämä käärö mukaasi ja laula sen mukaisesti näkemäsi sisäänkäynnin luona." ->
+ Some((me: Villager) =>
+ me.location.addItem(SeparatorScroll)
+ Event(immutable.Map.empty, "Tietäjä loihtii esiin laulukäärön, joka leijailee maahan jalkojesi juureen.")
+ ),
+ "Onnea matkaan. Muista valmistautua huolella, ennen kuin avaat portin." ->
+ None
)
+ )
+ val uolevi = Villager(this, "Uolevi", southForest,
+ Vector(
+ "Tunnen synkeän pulssin, joka virtaa tämän kiven alla. Uskon, että tämä on jonkinlainen sisäänkäynti, mutta en tunne sitä avaavaa loitsua. Mene sinä sen erakoituneen tietäjän luokse pyytämään neuvoa, niin minä jään tänne pitämään vahtia." ->
+ Some((me: Entity) =>
+ this.npcs += hermit.name -> hermit
+ this.hutInFieldForest.addEntity(hermit)
+ Event(immutable.Map.empty, "")
+ )
+ ,
+ "Ai, et tiedä sitä erakkoa? Löydät hänen majansa kyllä kylän eteläpuolelta." -> None
+ )
+ )
- 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)
+ val cultist1 = Cultist(this, "Kaapupäinen henkilö", secondCaveDescent)
+ val cultist2 = Cultist(this, "Silmätön kaljupää", secondCaveDescent)
+ val cultist3 = Cultist(this, "Silmitön kaljupää", otherCaveRoom)
+
+ val cthulthu = Cthulthu(this, bossFightRoom)
+ val miikkulainen = Miikkulainen(this, bossFightRoom)
- this.npcs += Bartender.name -> Bartender
- this.bar.addEntity(Bartender)
+ 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)
+ this.npcs += cultist1.name -> cultist1
+ this.secondCaveDescent.addEntity(cultist1)
+ this.npcs += cultist2.name -> cultist2
+ this.secondCaveDescent.addEntity(cultist2)
+ this.npcs += cultist3.name -> cultist3
+ this.otherCaveRoom.addEntity(cultist3)
+ this.npcs += uolevi.name -> uolevi
+ this.southForest.addEntity(uolevi)
+ this.npcs += cthulthu.name -> cthulthu
+ this.bossFightRoom.addEntity(cthulthu)
+ this.npcs += miikkulainen.name -> miikkulainen
+ this.bossFightRoom.addEntity(miikkulainen)
+
+
+ // Public methods
def takeNpcTurns(): Unit =
npcs.values.foreach(_.act())
diff --git a/src/scalevalapokalypsi/Model/Entities/Entity.scala b/src/scalevalapokalypsi/Model/Entities/Entity.scala
index 6a2072d..c3be227 100644
--- a/src/scalevalapokalypsi/Model/Entities/Entity.scala
+++ b/src/scalevalapokalypsi/Model/Entities/Entity.scala
@@ -31,7 +31,10 @@ class Entity(
* @return the verse to sing against this entity
*/
def getVerseAgainst: Vector[String] =
- Vector("Esimerkkirivi laulettavaksi")
+ Vector(
+ "Suohon sinut juuri laulan",
+ "saat maistaa mudan sekä taulan"
+ )
def isAlive = this.hp > 0
@@ -127,7 +130,7 @@ class Entity(
this.items += i.name -> (1, i)
Event(
Vector((this, s"Poimit esineen ${i.name}")).toMap,
- s"$name poimi esineen ${i.name}"
+ s"$name poimi esineen ${i.name}."
)
case None =>
Event(
diff --git a/src/scalevalapokalypsi/Model/Entities/NPCs/Cthulthu.scala b/src/scalevalapokalypsi/Model/Entities/NPCs/Cthulthu.scala
new file mode 100644
index 0000000..a8384f2
--- /dev/null
+++ b/src/scalevalapokalypsi/Model/Entities/NPCs/Cthulthu.scala
@@ -0,0 +1,48 @@
+
+
+package scalevalapokalypsi.Model.Entities.NPCs
+
+import scala.collection.mutable.Buffer
+import scalevalapokalypsi.Model.*
+import scalevalapokalypsi.Model.Entities.*
+import scala.util.Random
+
+class Cthulthu(
+ adventure: Adventure,
+ initialLocation: Area,
+ initialHP: Int = 100
+) extends NPC(adventure, "Leijuva lonkero-otus", initialLocation, initialHP, 100):
+
+ private var tentacleIndex = 0
+ private var hp = this.maxHP
+ override def isAlive = this.hp > 0
+
+ def heal(): Boolean =
+ if this.hp < this.maxHP then
+ this.hp = this.maxHP
+ true
+ else
+ false
+
+ override def getDialog: String =
+ "sxaCHReeaaaAAARRR!!"
+
+ override def act(): Unit =
+ val playersExist = this.location
+ .getEntities
+ .exists(_ match
+ case p: Player => true
+ case other => false
+ )
+ if playersExist then
+ this.location.addEntity(Tentacle(
+ adventure,
+ s"Lonkero #$tentacleIndex",
+ this.location
+ ))
+ this.location.observeEvent(
+ Event(Map.empty, s"${this.name} ärjyy. Maasta ilmestyy uusi lonkero.")
+ )
+
+end Cthulthu
+
diff --git a/src/scalevalapokalypsi/Model/Entities/NPCs/Cultist.scala b/src/scalevalapokalypsi/Model/Entities/NPCs/Cultist.scala
index fa5602e..c5c8789 100644
--- a/src/scalevalapokalypsi/Model/Entities/NPCs/Cultist.scala
+++ b/src/scalevalapokalypsi/Model/Entities/NPCs/Cultist.scala
@@ -11,7 +11,7 @@ class Cultist(
identifier: String,
initialLocation: Area,
initialHP: Int = 100,
- maxHP: Int = 100
+ maxHP: Int = 50
) extends NPC(adventure, identifier, initialLocation, initialHP, maxHP):
private val damage = 20
@@ -25,6 +25,7 @@ class Cultist(
.filter(_ != this)
.filter(_ match
case c: Cultist => false
+ case z: Zombie => false
case other => true
)
.toVector
@@ -35,6 +36,16 @@ class Cultist(
this.location.observeEvent(
this.curse(possibleVictims(index))
)
+ else
+ val possibleDirections = this.location.getNeighborNames
+ if possibleDirections.size != 0 then
+ val directionIndex = Random.between(
+ 0,
+ possibleDirections.size
+ )
+ this.go(possibleDirections.toVector(directionIndex)).foreach(
+ this.location.observeEvent(_)
+ )
private def curse(entity: Entity): Event =
diff --git a/src/scalevalapokalypsi/Model/Entities/NPCs/Miikkulainen.scala b/src/scalevalapokalypsi/Model/Entities/NPCs/Miikkulainen.scala
new file mode 100644
index 0000000..afaf702
--- /dev/null
+++ b/src/scalevalapokalypsi/Model/Entities/NPCs/Miikkulainen.scala
@@ -0,0 +1,33 @@
+
+
+
+package scalevalapokalypsi.Model.Entities.NPCs
+
+import scala.collection.mutable.Buffer
+import scalevalapokalypsi.Model.*
+import scalevalapokalypsi.Model.Entities.*
+import scala.util.Random
+
+class Miikkulainen(
+ adventure: Adventure,
+ initialLocation: Area,
+ initialHP: Int = 50
+) extends NPC(adventure, "Kultisti Miikkulainen", initialLocation, initialHP, 50):
+
+ override def getDialog: String =
+ "Koskaan ei tuhota Miikkulaisen päitä"
+
+ override def act(): Unit =
+ val cthulthu = this.location
+ .getEntities
+ .foreach(_ match
+ case c: Cthulthu =>
+ if c.heal() then
+ this.location.observeEvent(
+ Event(Map.empty, s"${this.name} vuodattaa verta ranteestaan. ${c.name} näyttää virkistyvän.")
+ )
+ case other => ()
+ )
+
+end Miikkulainen
+
diff --git a/src/scalevalapokalypsi/Model/Entities/NPCs/Tentacle.scala b/src/scalevalapokalypsi/Model/Entities/NPCs/Tentacle.scala
new file mode 100644
index 0000000..8535551
--- /dev/null
+++ b/src/scalevalapokalypsi/Model/Entities/NPCs/Tentacle.scala
@@ -0,0 +1,59 @@
+
+
+package scalevalapokalypsi.Model.Entities.NPCs
+
+import scala.collection.mutable.Buffer
+import scalevalapokalypsi.Model.*
+import scalevalapokalypsi.Model.Entities.*
+import scala.util.Random
+
+class Tentacle(
+ adventure: Adventure,
+ identifier: String,
+ initialLocation: Area,
+) extends NPC(adventure, identifier, initialLocation, 10, 10):
+
+ private val damage = 5
+ private val dialogs = Vector(
+ "splish",
+ "splosh"
+ )
+
+ 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 t: Tentacle => false
+ case m: Miikkulainen => false
+ case c: Cthulthu => 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 =
+ entity.takeDamage(this.damage)
+ Event(
+ Map.from(Vector((
+ entity,
+ s"${this.name} iskee sinua!\n" +
+ s"${entity.condition(0)}"
+ ))),
+ s"${this.name} iskee henkilöä ${entity.name}.\n" +
+ s"${entity.condition(1)}"
+ )
+
+end Tentacle
+
diff --git a/src/scalevalapokalypsi/Model/Entities/NPCs/Villager.scala b/src/scalevalapokalypsi/Model/Entities/NPCs/Villager.scala
new file mode 100644
index 0000000..1b9629f
--- /dev/null
+++ b/src/scalevalapokalypsi/Model/Entities/NPCs/Villager.scala
@@ -0,0 +1,79 @@
+
+package scalevalapokalypsi.Model.Entities.NPCs
+
+import scalevalapokalypsi.Model.{Area,Event,Item,Adventure}
+
+class Villager(
+ adventure: Adventure,
+ name: String,
+ initialLocation: Area,
+ dialogs: Vector[(String, Option[Villager => Event])]
+) extends NPC(adventure, name, initialLocation, 100, 100):
+
+ private var dialogIndex = 0
+
+ def getDialog: String =
+ val (dialog, effect) = this.dialogs(dialogIndex)
+ effect.map(_(this)).map(this.location.observeEvent(_))
+ this.dialogIndex +=
+ (if dialogIndex < this.dialogs.length-1
+ then 1
+ else 0)
+ dialog
+
+ def act(): Unit = ()
+
+end Villager
+
+/*
+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/Zombie.scala b/src/scalevalapokalypsi/Model/Entities/NPCs/Zombie.scala
index 56cb160..0c9ee84 100644
--- a/src/scalevalapokalypsi/Model/Entities/NPCs/Zombie.scala
+++ b/src/scalevalapokalypsi/Model/Entities/NPCs/Zombie.scala
@@ -23,6 +23,12 @@ class Zombie(
"öub gpa"
)
+ override def getVerseAgainst =
+ Vector(
+ "Suohon sula kuvajainen",
+ "maahan maadu paisenaama"
+ )
+
override def getDialog: String =
val dialogIndex = Random.between(0, this.dialogs.length)
this.dialogs(dialogIndex)
diff --git a/src/scalevalapokalypsi/Server/Client.scala b/src/scalevalapokalypsi/Server/Client.scala
index 940888b..becca32 100644
--- a/src/scalevalapokalypsi/Server/Client.scala
+++ b/src/scalevalapokalypsi/Server/Client.scala
@@ -204,7 +204,7 @@ class Client(val socket: Socket):
if this.verseIndex == this.versesToSing.length then
val timeQuality =
5.0*this.versesToSing.length /
- max(5.0, currentTimeMillis()/1000 - t)
+ max(5, currentTimeMillis()/1000 - t).toDouble
val songToSing = this.versesToSing.mkString("")
.toLowerCase
@@ -217,8 +217,9 @@ class Client(val socket: Socket):
)
this.player.foreach(_.applySingEffect(quality.toFloat))
-
+
this.singStartTime = None
+
else
this.versesSung += line
this.startVerse()
diff --git a/src/scalevalapokalypsi/Server/Server.scala b/src/scalevalapokalypsi/Server/Server.scala
index 6bf21d4..d0bb402 100644
--- a/src/scalevalapokalypsi/Server/Server.scala
+++ b/src/scalevalapokalypsi/Server/Server.scala
@@ -102,7 +102,7 @@ class Server(
val joinEvent = c.player.map(p => Event(
Map.from(Vector((p, ""))),
- s"${p.name} joins the game."
+ s"${p.name} liittyy peliin."
))
joinEvent.foreach(ev => this.clients.foreach(cl =>
if cl != c then
diff --git a/src/scalevalapokalypsi/constants/constants.scala b/src/scalevalapokalypsi/constants/constants.scala
index 159a153..268e5b2 100644
--- a/src/scalevalapokalypsi/constants/constants.scala
+++ b/src/scalevalapokalypsi/constants/constants.scala
@@ -13,7 +13,7 @@ val ACTION_NONBLOCKING_INDICATOR='+'
val INITIAL_CONN_TIMEOUT = 5000 // millisec.
val DEFAULT_PORT: Int = 2267
val DEFAULT_TURN_TIME_LIMIT = 30
-val DEFAULT_SERVER = "cron4.fi"
+val DEFAULT_SERVER = "dev.cron4.fi"
val LIST_SEPARATOR=";"
diff --git a/src/scalevalapokalypsi/utils/utils.scala b/src/scalevalapokalypsi/utils/utils.scala
index 4be0687..8179585 100644
--- a/src/scalevalapokalypsi/utils/utils.scala
+++ b/src/scalevalapokalypsi/utils/utils.scala
@@ -28,7 +28,7 @@ def byteArrayToString(bytes: Array[Byte]): Option[String] =
/** Incredibly LÖRS string metric algorithm.
* LÖRSiness explained by there being 6 hours left to the DL
*/
-def hammingDistance(s1: String, s2: String): Float =
+def hammingDistance(s1: String, s2: String): Int =
s1.zip(s2).map(p => p(0) != p(1)).filter((b: Boolean) => b).length
/** Reads n characters from the given InputStream blockingly.