working proof-of-concept inventory system

Former-commit-id: 1be5d6d10d0a5c93bceaf12f15d2ee50602cb602
Former-commit-id: 44f25a27c3b5d196210f4efcc3fef4dec8e30ff7
This commit is contained in:
Song Minjae
2016-12-14 15:41:20 +09:00
parent 7078ecfed4
commit 1d1769a2c3
7 changed files with 153 additions and 80 deletions

View File

@@ -60,9 +60,9 @@ constructor() : BasicGameState() {
lateinit var debugWindow: UIHandler lateinit var debugWindow: UIHandler
lateinit var notifier: UIHandler lateinit var notifier: UIHandler
lateinit internal var playableActorDelegate: PlayableActorDelegate internal var playableActorDelegate: PlayableActorDelegate? = null
internal val player: ActorHumanoid // currently POSSESSED actor :) internal val player: ActorHumanoid // currently POSSESSED actor :)
get() = playableActorDelegate.actor get() = playableActorDelegate!!.actor
//private var GRADIENT_IMAGE: Image? = null //private var GRADIENT_IMAGE: Image? = null
//private var skyBox: Rectangle? = null //private var skyBox: Rectangle? = null

View File

@@ -11,27 +11,29 @@ import net.torvald.terrarum.itemproperties.ItemPropCodex
*/ */
internal object Inventory : ConsoleCommand { internal object Inventory : ConsoleCommand {
private var target: ActorInventory = Terrarum.ingame.player.inventory private var target: Pocketed = Terrarum.ingame.player
override fun execute(args: Array<String>) { override fun execute(args: Array<String>) {
if (args.size == 1) { if (args.size == 1) {
printUsage() printUsage()
} else { }
else {
when (args[1]) { when (args[1]) {
"list" -> listInventory() "list" -> listInventory()
"add" -> addItem(args[2].toInt(), args[3].toInt()) "add" -> addItem(args[2].toInt(), args[3].toInt())
"target" -> setTarget(args[2].toInt()) "target" -> setTarget(args[2].toInt())
"assign" -> assignQuickBar(args[2].toInt(), args[3].toInt()) "hold" -> holdItem(args[2].toInt())
else -> printUsage() else -> printUsage()
} }
} }
} }
private fun listInventory() { private fun listInventory() {
if (target.getTotalUniqueCount() == 0) { if (target.inventory.getTotalUniqueCount() == 0) {
Echo("(inventory empty)") Echo("(inventory empty)")
} else { }
target.forEach { refId, amount -> else {
target.inventory.forEach { refId, amount ->
if (amount == 0) { if (amount == 0) {
EchoError("Unexpected zero-amounted item: ID $refId") EchoError("Unexpected zero-amounted item: ID $refId")
} }
@@ -44,22 +46,29 @@ internal object Inventory : ConsoleCommand {
val actor = Terrarum.ingame.getActorByID(actorRefId) val actor = Terrarum.ingame.getActorByID(actorRefId)
if (actor !is Pocketed) { if (actor !is Pocketed) {
EchoError("Cannot edit inventory of incompatible actor: $actor") EchoError("Cannot edit inventory of incompatible actor: $actor")
} else { }
target = actor.inventory else {
target = actor
} }
} }
private fun addItem(refId: Int, amount: Int = 1) { private fun addItem(refId: Int, amount: Int = 1) {
target.add(ItemPropCodex.getProp(refId), amount) target.inventory.add(ItemPropCodex.getProp(refId), amount)
} }
private fun assignQuickBar(refId: Int, index: Int) { private fun holdItem(refId: Int) {
// if the item does not exist, add it first
if (!target.inventory.contains(refId)) {
target.inventory.add(refId)
}
target.itemHolding = ItemPropCodex.getProp(refId)
} }
override fun printUsage() { override fun printUsage() {
Echo("Usage: inventory command arguments") Echo("Usage: inventory command arguments")
Echo("Available commands:") Echo("Available commands:")
Echo("list | assign slot | add itemid [amount] | target [actorid]") Echo("list | assign slot | add itemid [amount] | target [actorid] | hold itemid")
Echo("equip itemid")
} }
} }

View File

@@ -7,6 +7,7 @@ import net.torvald.terrarum.gameactors.faction.Faction
import net.torvald.terrarum.gamecontroller.EnumKeyFunc import net.torvald.terrarum.gamecontroller.EnumKeyFunc
import net.torvald.terrarum.gamecontroller.KeyMap import net.torvald.terrarum.gamecontroller.KeyMap
import net.torvald.terrarum.gameitem.InventoryItem import net.torvald.terrarum.gameitem.InventoryItem
import net.torvald.terrarum.gameitem.InventoryItemAdapter
import net.torvald.terrarum.realestate.RealEstateUtility import net.torvald.terrarum.realestate.RealEstateUtility
import org.dyn4j.geometry.Vector2 import org.dyn4j.geometry.Vector2
import org.lwjgl.input.Controller import org.lwjgl.input.Controller
@@ -26,11 +27,8 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null)
/** Must be set by PlayerFactory */ /** Must be set by PlayerFactory */
override var inventory: ActorInventory = ActorInventory() override var inventory: ActorInventory = ActorInventory()
override var itemHolding: InventoryItem override var itemHolding: InventoryItem? = null
get() = throw TODO("itemHolding") override val itemEquipped = ArrayList<InventoryItem>()
set(value) {
throw TODO("itemHolding")
}
/** Must be set by PlayerFactory */ /** Must be set by PlayerFactory */
override var faction: HashSet<Faction> = HashSet() override var faction: HashSet<Faction> = HashSet()
@@ -136,6 +134,13 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null)
get() = this is Player // FIXME true iff composed by PlayableActorDelegate get() = this is Player // FIXME true iff composed by PlayableActorDelegate
private val nullItem = object : InventoryItemAdapter() {
override val itemID: Int = 0
override var mass: Double = 0.0
override var scale: Double = 1.0
}
override fun update(gc: GameContainer, delta: Int) { override fun update(gc: GameContainer, delta: Int) {
super.update(gc, delta) super.update(gc, delta)
@@ -206,12 +211,12 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null)
*/ */
// Left mouse // Left mouse
if (isGamer && input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) { if (isGamer && input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) {
itemHolding.primaryUse(gc, delta) (itemHolding ?: nullItem).primaryUse(gc, delta)
} }
// Right mouse // Right mouse
if (isGamer && input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON)) { if (isGamer && input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON)) {
itemHolding.secondaryUse(gc, delta) (itemHolding ?: nullItem).secondaryUse(gc, delta)
} }
/** /**

View File

@@ -51,6 +51,43 @@ class ActorInventory() {
} }
} }
fun add(item: InventoryItem, count: Int = 1) = add(item.itemID, count)
fun add(itemID: Int, count: Int = 1) {
if (itemID == Player.PLAYER_REF_ID)
throw IllegalArgumentException("Attempted to put human player into the inventory.")
if (Terrarum.ingame.playableActorDelegate != null &&
itemID == Terrarum.ingame.player.referenceID)
throw IllegalArgumentException("Attempted to put active player into the inventory.")
// If we already have the item, increment the amount
// If not, add item with specified amount
itemList.put(itemID, itemList[itemID] ?: 0 + count)
}
fun remove(item: InventoryItem, count: Int = 1) = remove(item.itemID, count)
fun remove(itemID: Int, count: Int = 1) {
// check if the item does NOT exist
if (itemList[itemID] == null) {
return
}
else {
// remove the existence of the item if count <= 0
if (itemList[itemID]!! - count <= 0) {
itemList.remove(itemID)
}
// else, decrement the item count
else {
itemList.put(itemID, itemList[itemID]!! - count)
}
}
}
fun contains(item: InventoryItem) = itemList.containsKey(item.itemID)
fun contains(itemID: Int) = itemList.containsKey(itemID)
fun forEach(consumer: (Int, Int) -> Unit) = itemList.forEach(consumer)
/** /**
* Get capacity of inventory * Get capacity of inventory
* @return * @return
@@ -79,8 +116,6 @@ class ActorInventory() {
return itemList return itemList
} }
fun forEach(consumer: (Int, Int) -> Unit) = itemList.forEach(consumer)
/** /**
* Get clone of the itemList * Get clone of the itemList
* @return * @return
@@ -120,21 +155,6 @@ class ActorInventory() {
return itemList.entries.size return itemList.entries.size
} }
fun add(item: InventoryItem) {
add(item, 1)
}
fun add(item: InventoryItem, count: Int) {
val key = item.itemID
if (key == Player.PLAYER_REF_ID || key == Terrarum.ingame.player.referenceID)
throw IllegalArgumentException("Attempted to put active player or human player into the inventory.")
// If we already have the item, increment the amount
// If not, add item with specified amount
itemList.put(key, itemList[key] ?: 0 + count)
}
/** /**
* Check whether the itemList contains too many items * Check whether the itemList contains too many items
* @return * @return

View File

@@ -53,10 +53,14 @@ open class ActorWithBody : Actor() {
internal val velocity = Vector2(0.0, 0.0) internal val velocity = Vector2(0.0, 0.0)
var veloX: Double var veloX: Double
get() = velocity.x get() = velocity.x
protected set(value) { velocity.x = value } protected set(value) {
velocity.x = value
}
var veloY: Double var veloY: Double
get() = velocity.y get() = velocity.y
protected set(value) { velocity.y = value } protected set(value) {
velocity.y = value
}
val moveDelta = Vector2(0.0, 0.0) val moveDelta = Vector2(0.0, 0.0)
@Transient private val VELO_HARD_LIMIT = 100.0 @Transient private val VELO_HARD_LIMIT = 100.0
@@ -67,10 +71,14 @@ open class ActorWithBody : Actor() {
var controllerVel: Vector2? = if (this is Controllable) Vector2() else null var controllerVel: Vector2? = if (this is Controllable) Vector2() else null
var walkX: Double var walkX: Double
get() = controllerVel!!.x get() = controllerVel!!.x
protected set(value) { controllerVel!!.x = value } protected set(value) {
controllerVel!!.x = value
}
var walkY: Double var walkY: Double
get() = controllerVel!!.y get() = controllerVel!!.y
protected set(value) { controllerVel!!.y = value } protected set(value) {
controllerVel!!.y = value
}
/** /**
* Physical properties. * Physical properties.
@@ -114,7 +122,9 @@ open class ActorWithBody : Actor() {
* Formula: restitution = 1.0 - elasticity * Formula: restitution = 1.0 - elasticity
*/ */
var restitution: Double var restitution: Double
set(value) { elasticity = 1.0 - value } set(value) {
elasticity = 1.0 - value
}
get() = 1.0 - elasticity get() = 1.0 - elasticity
@Transient private val CEILING_HIT_ELASTICITY = 0.3 @Transient private val CEILING_HIT_ELASTICITY = 0.3
@@ -363,7 +373,7 @@ open class ActorWithBody : Actor() {
} }
// cheap solution for sticking into the wall while Left or Right is held // cheap solution for sticking into the wall while Left or Right is held
walledLeft = isTouchingSide(nextHitbox, COLLIDING_LEFT) walledLeft = isTouchingSide(nextHitbox, COLLIDING_LEFT)
walledRight = isTouchingSide(nextHitbox, COLLIDING_RIGHT) walledRight = isTouchingSide(nextHitbox, COLLIDING_RIGHT)
if (isPlayerNoClip) { if (isPlayerNoClip) {
walledLeft = false walledLeft = false
@@ -462,7 +472,7 @@ open class ActorWithBody : Actor() {
} }
// axis X // axis X
if (isTouchingSide(nextHitbox, COLLIDING_LEFT) || isTouchingSide(nextHitbox, COLLIDING_RIGHT) if (isTouchingSide(nextHitbox, COLLIDING_LEFT) || isTouchingSide(nextHitbox, COLLIDING_RIGHT)
&& moveDelta.x != 0.0) { // check right and left && moveDelta.x != 0.0) { // check right and left
// the actor is hitting the wall // the actor is hitting the wall
hitAndReflectX() hitAndReflectX()
} }
@@ -475,7 +485,7 @@ open class ActorWithBody : Actor() {
private fun displaceByCCD() { private fun displaceByCCD() {
ccdCollided = false ccdCollided = false
if (!isNoCollideWorld){ if (!isNoCollideWorld) {
if (!isColliding(nextHitbox, COLLIDING_ALLSIDE)) if (!isColliding(nextHitbox, COLLIDING_ALLSIDE))
return return
@@ -534,7 +544,10 @@ open class ActorWithBody : Actor() {
if (isNoCollideWorld) return false if (isNoCollideWorld) return false
// offsets will stretch and shrink detection box according to the argument // offsets will stretch and shrink detection box according to the argument
val x1: Double; val x2: Double; val y1: Double; val y2: Double val x1: Double;
val x2: Double;
val y1: Double;
val y2: Double
if (option == COLLIDING_LR || option == COLLIDING_UD) { if (option == COLLIDING_LR || option == COLLIDING_UD) {
val offsetX = if (option == COLLIDING_LR) A_PIXEL else 0.0 val offsetX = if (option == COLLIDING_LR) A_PIXEL else 0.0
val offsetY = if (option == COLLIDING_UD) A_PIXEL else 0.0 val offsetY = if (option == COLLIDING_UD) A_PIXEL else 0.0
@@ -578,15 +591,18 @@ open class ActorWithBody : Actor() {
} }
val txStart = x1.div(TSIZE).floorInt() val txStart = x1.div(TSIZE).floorInt()
val txEnd = x2.div(TSIZE).floorInt() val txEnd = x2.div(TSIZE).floorInt()
val tyStart = y1.div(TSIZE).floorInt() val tyStart = y1.div(TSIZE).floorInt()
val tyEnd = y2.div(TSIZE).floorInt() val tyEnd = y2.div(TSIZE).floorInt()
return isCollidingInternal(txStart, tyStart, txEnd, tyEnd) return isCollidingInternal(txStart, tyStart, txEnd, tyEnd)
} }
private fun isTouchingSide(hitbox: Hitbox, option: Int): Boolean { private fun isTouchingSide(hitbox: Hitbox, option: Int): Boolean {
val x1: Double; val x2: Double; val y1: Double; val y2: Double val x1: Double;
val x2: Double;
val y1: Double;
val y2: Double
if (option == COLLIDING_TOP) { if (option == COLLIDING_TOP) {
x1 = hitbox.posX x1 = hitbox.posX
x2 = hitbox.endPointX x2 = hitbox.endPointX
@@ -614,16 +630,19 @@ open class ActorWithBody : Actor() {
else throw IllegalArgumentException() else throw IllegalArgumentException()
val txStart = x1.div(TSIZE).floorInt() val txStart = x1.div(TSIZE).floorInt()
val txEnd = x2.div(TSIZE).floorInt() val txEnd = x2.div(TSIZE).floorInt()
val tyStart = y1.div(TSIZE).floorInt() val tyStart = y1.div(TSIZE).floorInt()
val tyEnd = y2.div(TSIZE).floorInt() val tyEnd = y2.div(TSIZE).floorInt()
return isCollidingInternal(txStart, tyStart, txEnd, tyEnd) return isCollidingInternal(txStart, tyStart, txEnd, tyEnd)
} }
private fun isCollidingSide(hitbox: Hitbox, option: Int): Boolean { private fun isCollidingSide(hitbox: Hitbox, option: Int): Boolean {
val x1: Double; val x2: Double; val y1: Double; val y2: Double val x1: Double;
val x2: Double;
val y1: Double;
val y2: Double
if (option == COLLIDING_TOP) { if (option == COLLIDING_TOP) {
x1 = hitbox.posX x1 = hitbox.posX
x2 = hitbox.endPointX x2 = hitbox.endPointX
@@ -804,8 +823,8 @@ open class ActorWithBody : Actor() {
if (!isWalkingH) if (!isWalkingH)
Hitbox(nextHitbox.posX, nextHitbox.posY, Hitbox(nextHitbox.posX, nextHitbox.posY,
nextHitbox.width + 2.0, nextHitbox.height + 2.0) nextHitbox.width + 2.0, nextHitbox.height + 2.0)
// when not walking, enlarge the hitbox for calculation so that // when not walking, enlarge the hitbox for calculation so that
// feet tiles are also counted // feet tiles are also counted
else else
nextHitbox.clone() nextHitbox.clone()
@@ -823,6 +842,7 @@ open class ActorWithBody : Actor() {
return friction return friction
} }
fun Int.tileFrictionToMult(): Double = this / 16.0 fun Int.tileFrictionToMult(): Double = this / 16.0
/** /**
@@ -908,7 +928,8 @@ open class ActorWithBody : Actor() {
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(), (hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
(scale).toFloat() (scale).toFloat()
) )
} else { }
else {
spriteGlow!!.render(g, spriteGlow!!.render(g,
(hitbox.posX - scale).toFloat(), (hitbox.posX - scale).toFloat(),
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(), (hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
@@ -921,9 +942,9 @@ open class ActorWithBody : Actor() {
open fun drawBody(gc: GameContainer, g: Graphics) { open fun drawBody(gc: GameContainer, g: Graphics) {
if (isVisible && sprite != null) { if (isVisible && sprite != null) {
when (drawMode) { when (drawMode) {
DrawMode.NORMAL -> blendNormal() DrawMode.NORMAL -> blendNormal()
DrawMode.MULTIPLY -> blendMul() DrawMode.MULTIPLY -> blendMul()
DrawMode.SCREEN -> blendScreen() DrawMode.SCREEN -> blendScreen()
} }
if (!sprite!!.flippedHorizontal()) { if (!sprite!!.flippedHorizontal()) {
@@ -932,7 +953,8 @@ open class ActorWithBody : Actor() {
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(), (hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
(scale).toFloat() (scale).toFloat()
) )
} else { }
else {
sprite!!.render(g, sprite!!.render(g,
(hitbox.posX - scale).toFloat(), (hitbox.posX - scale).toFloat(),
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(), (hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
@@ -951,22 +973,26 @@ open class ActorWithBody : Actor() {
} }
private fun clampW(x: Double): Double = private fun clampW(x: Double): Double =
if (x < TSIZE + nextHitbox.width / 2) { if (x < TSIZE + nextHitbox.width / 2) {
TSIZE + nextHitbox.width / 2 TSIZE + nextHitbox.width / 2
} else if (x >= (world.width * TSIZE).toDouble() - TSIZE.toDouble() - nextHitbox.width / 2) { }
(world.width * TSIZE).toDouble() - 1.0 - TSIZE.toDouble() - nextHitbox.width / 2 else if (x >= (world.width * TSIZE).toDouble() - TSIZE.toDouble() - nextHitbox.width / 2) {
} else { (world.width * TSIZE).toDouble() - 1.0 - TSIZE.toDouble() - nextHitbox.width / 2
x }
} else {
x
}
private fun clampH(y: Double): Double = private fun clampH(y: Double): Double =
if (y < TSIZE + nextHitbox.height) { if (y < TSIZE + nextHitbox.height) {
TSIZE + nextHitbox.height TSIZE + nextHitbox.height
} else if (y >= (world.height * TSIZE).toDouble() - TSIZE.toDouble() - nextHitbox.height) { }
(world.height * TSIZE).toDouble() - 1.0 - TSIZE.toDouble() - nextHitbox.height else if (y >= (world.height * TSIZE).toDouble() - TSIZE.toDouble() - nextHitbox.height) {
} else { (world.height * TSIZE).toDouble() - 1.0 - TSIZE.toDouble() - nextHitbox.height
y }
} else {
y
}
private fun clampWtile(x: Int): Int = private fun clampWtile(x: Int): Int =
if (x < 0) 0 else if (x >= world.width) world.width - 1 else x if (x < 0) 0 else if (x >= world.width) world.width - 1 else x
@@ -995,7 +1021,9 @@ open class ActorWithBody : Actor() {
assertPrinted = true assertPrinted = true
} }
internal fun flagDespawn() { flagDespawn = true } internal fun flagDespawn() {
flagDespawn = true
}
companion object { companion object {
@@ -1037,23 +1065,25 @@ fun Double.sqr() = this * this
fun Double.sqrt() = Math.sqrt(this) fun Double.sqrt() = Math.sqrt(this)
fun Int.abs() = if (this < 0) -this else this fun Int.abs() = if (this < 0) -this else this
fun Double.bipolarClamp(limit: Double) = fun Double.bipolarClamp(limit: Double) =
if (this > 0 && this > limit) limit if (this > 0 && this > limit) limit
else if (this < 0 && this < -limit) -limit else if (this < 0 && this < -limit) -limit
else this else this
fun absMax(left: Double, right: Double): Double { fun absMax(left: Double, right: Double): Double {
if (left > 0 && right > 0) if (left > 0 && right > 0)
if (left > right) return left if (left > right) return left
else return right else return right
else if (left < 0 && right < 0) else if (left < 0 && right < 0)
if (left < right) return left if (left < right) return left
else return right else return right
else { else {
val absL = left.abs() val absL = left.abs()
val absR = right.abs() val absR = right.abs()
if (absL > absR) return left if (absL > absR) return left
else return right else return right
} }
} }
fun Double.magnSqr() = if (this >= 0.0) this.sqr() else -this.sqr() fun Double.magnSqr() = if (this >= 0.0) this.sqr() else -this.sqr()
fun Double.sign() = if (this > 0.0) 1.0 else if (this < 0.0) -1.0 else 0.0 fun Double.sign() = if (this > 0.0) 1.0 else if (this < 0.0) -1.0 else 0.0

View File

@@ -6,6 +6,7 @@ import net.torvald.spriteanimation.SpriteAnimation
import com.google.gson.JsonObject import com.google.gson.JsonObject
import net.torvald.terrarum.gameactors.ActorHumanoid import net.torvald.terrarum.gameactors.ActorHumanoid
import net.torvald.terrarum.gameactors.faction.FactionFactory import net.torvald.terrarum.gameactors.faction.FactionFactory
import net.torvald.terrarum.itemproperties.ItemPropCodex
import net.torvald.terrarum.mapdrawer.MapDrawer import net.torvald.terrarum.mapdrawer.MapDrawer
import org.newdawn.slick.SlickException import org.newdawn.slick.SlickException
import java.io.IOException import java.io.IOException
@@ -74,7 +75,8 @@ object PlayerBuilderSigrid {
// Test fill up inventory // Test fill up inventory
p.inventory.add(16)
p.itemHolding = ItemPropCodex.getProp(16)

View File

@@ -1,6 +1,7 @@
package net.torvald.terrarum.gameactors package net.torvald.terrarum.gameactors
import net.torvald.terrarum.gameitem.InventoryItem import net.torvald.terrarum.gameitem.InventoryItem
import java.util.*
/** /**
* Created by minjaesong on 16-01-15. * Created by minjaesong on 16-01-15.
@@ -9,7 +10,13 @@ interface Pocketed {
var inventory: ActorInventory var inventory: ActorInventory
/** Item currentry holding, like tools/weapons/scrolls/magic/etc. */ /** Item currentry holding, like tools/weapons/scrolls/magic/etc.
var itemHolding: InventoryItem * Null if not holding anything
*/
var itemHolding: InventoryItem?
/**
* List of all equipped items (tools, armours, rings, necklaces, etc.)
*/
val itemEquipped: ArrayList<InventoryItem>
} }