Skip to content

Fixes #49: Character cannot have two equal items #90

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ sudo: false
language: scala
jdk: openjdk11
scala:
- 2.11.6
- 2.13.1
script: sbt test site
notifications:
email:
Expand Down
13 changes: 7 additions & 6 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ name := "Keter"

version := "0.0.1"

scalaVersion := "2.11.12"
scalaVersion := "2.13.1"

libraryDependencies ++= Seq(
"com.lihaoyi" %%% "utest" % "0.3.1",
"org.scala-js" %%% "scalajs-dom" % "0.8.0",
"org.webjars" % "rot.js" % "0.5.0"
"com.lihaoyi" %%% "utest" % "0.7.2",
"org.scala-js" %%% "scalajs-dom" % "0.9.8",
"org.webjars" % "rot.js" % "0.5.0",
"org.scala-lang.modules" %%% "scala-collection-contrib" % "0.2.1"
)

npmDependencies in Compile += "rot-js" -> "0.6.2"
Expand All @@ -33,8 +34,8 @@ site := {
import java.nio.file.{Files, StandardCopyOption}
(webpack in fullOptJS in Compile).value
val targetDirectory = target.value / sitePath.value
val sourceJS = target.value / "scala-2.11" / "scalajs-bundler" / "main" / "keter-opt-bundle.js"
val sourceMap = target.value / "scala-2.11" / "scalajs-bundler" / "main" / "keter-opt-bundle.js.map"
val sourceJS = target.value / "scala-2.13" / "scalajs-bundler" / "main" / "keter-opt-bundle.js"
val sourceMap = target.value / "scala-2.13" / "scalajs-bundler" / "main" / "keter-opt-bundle.js.map"
val targetJS = targetDirectory / "keter.js"
val targetMap = targetDirectory / sourceMap.name
targetJS.mkdirs()
Expand Down
4 changes: 2 additions & 2 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.25")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.31")

addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.14.0")
addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler-sjs06" % "0.16.0")
2 changes: 1 addition & 1 deletion src/main/scala/ru/org/codingteam/keter/game/IEngine.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ package ru.org.codingteam.keter.game


trait IEngine {
def addMessage(msg: String)
def addMessage(msg: String): Unit
}
2 changes: 1 addition & 1 deletion src/main/scala/ru/org/codingteam/keter/game/Location.scala
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ object Location extends Logging {
submap = submap1,
coords = skel1.coordsOf('@').coords,
subspaceMatrix = SubspaceMatrix.identity),
items = Set(Knife("Knife"))
items = Set(Knife("Knife"), Knife("Knife"), Knife("Knife"))
)

val scp = human(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import scala.collection.SortedMap
sealed class EventQueue(val timestamp: Double, events: SortedMap[Double, Seq[ScheduledEvent]]) {

def addEvent(at: Double, event: ScheduledEvent): EventQueue = {
new EventQueue(timestamp, events + (at -> (events.getOrElse(at, IndexedSeq()) :+ event)))
new EventQueue(timestamp, events ++ Map(at -> (events.getOrElse(at, IndexedSeq()) :+ event)))
}

def nextEventTime: Option[Double] = events.headOption map (_._1)
Expand All @@ -19,7 +19,7 @@ sealed class EventQueue(val timestamp: Double, events: SortedMap[Double, Seq[Sch
require(events.nonEmpty, "Event queue is empty!")
events.head match {
case (at, Seq(action)) => new EventQueue(timestamp, events.tail)
case (at, actions) => new EventQueue(timestamp, events.tail + (at -> actions.tail))
case (at, actions) => new EventQueue(timestamp, events.tail ++ Map(at -> actions.tail))
}
}

Expand All @@ -29,5 +29,7 @@ sealed class EventQueue(val timestamp: Double, events: SortedMap[Double, Seq[Sch
}

object EventQueue {
import Ordering.Double.IeeeOrdering

val empty = new EventQueue(0, SortedMap())
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ case class Inventory(body: Set[Bodypart], equipment: Set[EquipmentItem], backpac
/**
* @return list of all inventory items either equipped or not.
*/
def allEquipment = equipment ++ backpack
def allEquipment: Set[EquipmentItem] = equipment ++ backpack
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ abstract class Weapon extends EquipmentItem {
def damage: Int
}

case class Knife(name: String,
damage: Int = 50) extends Weapon {
class Knife(private val _name: String, private val _damage: Int) extends Weapon {

val cooldown = 200
val missCooldown = 100
Expand All @@ -37,4 +36,14 @@ case class Knife(name: String,

override val requires: Set[Capability] = Set(ManipulatorCapability)

override def damage: Int = _damage

/**
* Name of equipment item.
*/
override def name: String = _name
}

object Knife {
def apply(name: String, damage: Int = 50) = new Knife(name, damage)
Copy link
Member

@ForNeVeR ForNeVeR Feb 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I dislike the approach taken. Now we'll be required to be very careful when declaring our item classes to not hit the same issue with any of them.

There's an alternate route with marking our items with identifiers (the same as we already use for actors and factions).

@ttldtor, what do you think about this alternative? Would it be worse?

Copy link
Member Author

@ttldtor ttldtor Feb 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ForNeVeR I don't see any faction id: case class Faction(name: String). Yep, I agree with you. I'll add id to items.

}
6 changes: 4 additions & 2 deletions src/main/scala/ru/org/codingteam/keter/map/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ package object map {
}

def nextEvent: Option[(Double, ScheduledEvent, UniverseSnapshot)] = {
import Ordering.Double.IeeeOrdering

val delays = (globalEvents.nextEventDelay map ((_, this))).toIndexedSeq ++
actors.values.flatMap(a => a.nextEventDelay.map((_, a)))
log.debug(s"Timestamp: ${globalEvents.timestamp}; First event count: ${delays.size}")
Expand All @@ -148,15 +150,15 @@ package object map {
val (nextTimestamp, nextAction) = globalEvents.nextEvent.get
val nextUniverse = copy(
globalEvents = globalEvents.dropNextEvent().addTime(delay),
actors = actors.mapValues(_.addTime(delay)))
actors = actors.view.mapValues(_.addTime(delay)).toMap)
log.debug(s"Event from universe, delay=$delay, next timestamp=$nextTimestamp")
(nextTimestamp, nextAction, nextUniverse)
case (delay, actor: ActorLike) =>
val nextTimestamp = globalEvents.timestamp + delay
val nextAction = actor.eventQueue.nextEvent.get._2
val nextUniverse = copy(
globalEvents = globalEvents.addTime(delay),
actors = actors.mapValues(_.addTime(delay))).updatedActor(actor.id)(_.dropNextEvent())
actors = actors.view.mapValues(_.addTime(delay)).toMap).updatedActor(actor.id)(_.dropNextEvent())
log.debug(s"Event from actor, delay=$delay, next timestamp=$nextTimestamp")
(nextTimestamp, nextAction, nextUniverse)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package ru.org.codingteam.keter.scenes.inventory

import ru.org.codingteam.keter.game.objects.Inventory
import ru.org.codingteam.keter.game.objects.equipment.EquipmentCategory._
import ru.org.codingteam.keter.game.objects.equipment.{EquipmentCategory, EquipmentItem}
import ru.org.codingteam.keter.game.objects.equipment.{Capability, EquipmentCategory, EquipmentItem}
import ru.org.codingteam.keter.ui.viewmodels.{ItemsViewModel, StaticTextViewModel}
import ru.org.codingteam.keter.util.VectorMap

import scala.collection.mutable
import scala.concurrent.Promise

class InventoryViewModel(var inventory: Inventory) {
Expand Down Expand Up @@ -33,20 +34,31 @@ class InventoryViewModel(var inventory: Inventory) {

val currentFolderItems = new ItemsViewModel[EquipmentItem](toVectorMap(inventory.allEquipment.toSeq)) {

def canEquip(item: EquipmentItem): Boolean = {
val inventoryProvidedCapabilities = inventory.body.foldLeft(mutable.MultiSet[Capability]())(_ ++= _.provides)
val inventoryRequiredCapabilities = inventory.equipment.foldLeft(mutable.MultiSet[Capability]())(_ ++= _.requires)

inventoryProvidedCapabilities --= inventoryRequiredCapabilities
(item.requires & inventoryProvidedCapabilities.toSet) == item.requires
}

def equipped(item: EquipmentItem): Boolean = {
inventory.equipment.contains(item)
}

def toggleSelected() = {
def toggleSelected(): Unit = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add a test for the new behavior of this method?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

selectedItem foreach { item =>
var backpack = inventory.backpack
var equipment = inventory.equipment

if (equipped(item)) {
equipment -= item
backpack += item
} else {
} else if (canEquip(item)) {
backpack -= item
equipment += item
} else {
return
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to return the missing capabilities from the canEquip method, log them here, and add a // TODO: Show missing capabilities on screen.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

inventory = inventory.copy(backpack = backpack, equipment = equipment)
Expand All @@ -58,6 +70,6 @@ class InventoryViewModel(var inventory: Inventory) {

private def toVectorMap(items: Seq[EquipmentItem]): VectorMap[EquipmentItem, String] = {
val itemsWithNames = items.map(equipment => (equipment, equipment.name))
VectorMap(itemsWithNames.toSeq: _*)
VectorMap(itemsWithNames: _*)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ object ChangeInventoryActionTest extends TestSuite {
val universe = Location.createLocation()
val action = InventoryChangeAction(Inventory(Set(Head("h", 10)), Set(Knife("k")), Set()))

val tests = TestSuite {
'shouldChangeInventory {
val tests = Tests {
test("shouldChangeInventory") {
val newState = action.perform(universe.playerId.get, universe)
val player = newState.player.get

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ object WaitActionTest extends TestSuite {
val universe = UniverseSnapshot(Map(), Some(playerId), EventQueue.empty)
val action = WaitAction(50.0)

val tests = TestSuite {
'shouldWait {
val tests = Tests {
test("shouldWait") {
val newState = action.perform(playerId, universe)
assert(newState == universe)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ru.org.codingteam.keter.game.objects

import ru.org.codingteam.keter.game.objects.equipment.items.Knife
import utest._

import scala.collection.MultiSet

object InventoryTest extends TestSuite {
val tests = Tests {
test("shouldSetTwoKnifes") {
val i = Inventory(Set(), Set(Knife("Knife")), Set(Knife("Knife")))
println(i.allEquipment)
assert(i.allEquipment.size == 2)
}
}
}