fresh-new dynamic items (e.g. pickaxe) can be stacked

This commit is contained in:
Song Minjae
2017-04-25 02:59:59 +09:00
parent c35ba8201a
commit ebc8174d2c
12 changed files with 102 additions and 47 deletions

View File

@@ -19,14 +19,14 @@ object AmmoMeterProxy {
}
else {
meter.vitalGetterVal = {
if (ItemCodex[currentItem.originalID].consumable)
if (ItemCodex[currentItem.originalID].stackable)
actor.inventory.getByDynamicID(currentItem.dynamicID)!!.amount.toFloat()
else
currentItem.durability
}
meter.vitalGetterMax = {
if (ItemCodex[currentItem.originalID].consumable)
if (ItemCodex[currentItem.originalID].stackable)
500f
else
currentItem.maxDurability.toFloat()

View File

@@ -73,7 +73,7 @@ class StateInGame : BasicGameState() {
get() = playableActorDelegate?.actor
var screenZoom = 1.0f
val ZOOM_MAX = 2.0f
val ZOOM_MAX = 4.0f
val ZOOM_MIN = 0.5f
val worldDrawFrameBuffer = Image(Terrarum.WIDTH.div(ZOOM_MIN).ceilInt(), Terrarum.HEIGHT.div(ZOOM_MIN).ceilInt())
@@ -317,9 +317,6 @@ class StateInGame : BasicGameState() {
/////////////////////////
// app-related updates //
/////////////////////////
if (!Terrarum.isWin81) {
Terrarum.appgc.setVSync(Terrarum.appgc.fps >= Terrarum.VSYNC_TRIGGER_THRESHOLD) // windows 10 has some trouble with this...
}
// determine if lightmap blending should be done
Terrarum.setConfig("smoothlighting", KeyToggler.isOn(KEY_LIGHTMAP_SMOOTH))

View File

@@ -56,7 +56,7 @@ class StateUITest : BasicGameState() {
override var inventoryCategory: String = InventoryItem.Category.TOOL
override var maxDurability: Int = 143
override var durability: Float = 64f
override var consumable = false
override var stackable = false
override val isDynamic = true
})
actor.inventory.getByDynamicID(5656)!!.item.name = "Test tool"
@@ -72,7 +72,7 @@ class StateUITest : BasicGameState() {
override var baseMass: Double = 1.4
override var baseToolSize: Double? = null
override var inventoryCategory: String = InventoryItem.Category.MISC
override var consumable = false
override var stackable = false
override val isDynamic = false
})

View File

@@ -93,7 +93,7 @@ class UIItemInventoryElem(
// this one-liner sets color
g.color = item!!.nameColour mul if (mouseUp) mouseOverTextCol else inactiveTextCol
g.drawString(
"$item" + (if (amount > 0 && !item!!.isUnique) "$fwsp($amount)" else "") +
"$item" + (if (amount > 0 && item!!.stackable) "$fwsp($amount)" else if (amount != 1) "$fwsp!!$amount!!" else "") +
//item!!.name + (if (amount > 0 && !item!!.isUnique) "$fwsp($amount)" else "") +
(if (equippedSlot != null) " ${0xE081.toChar()}\$$equippedSlot" else ""),
posX + textOffsetX,

View File

@@ -145,7 +145,7 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null)
override var baseToolSize: Double? = null
override var inventoryCategory = "should_not_be_seen"
override val originalName: String = actorValue.getAsString(AVKey.NAME) ?: "(no name)"
override var consumable = false
override var stackable = false
override val isDynamic = false
}

View File

@@ -3,6 +3,7 @@ package net.torvald.terrarum.gameactors
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.itemproperties.InventoryItem
import net.torvald.terrarum.itemproperties.ItemCodex
import net.torvald.terrarum.itemproperties.ItemCodex.ITEM_DYNAMIC
import net.torvald.terrarum.ui.UIInventory
import java.util.*
import java.util.concurrent.locks.Lock
@@ -36,11 +37,21 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode
fun add(itemID: Int, count: Int = 1) = add(ItemCodex[itemID], count)
fun add(item: InventoryItem, count: Int = 1) {
if (item.dynamicID == Player.PLAYER_REF_ID || item.dynamicID == 0x51621D) // do not delete this magic
println("[ActorInventory] add $item, $count")
if (count == 0)
throw IllegalArgumentException("Item count is zero.")
if (count < 0)
throw IllegalArgumentException("Item count is negative number. If you intended removing items, use remove()" +
"These commands are NOT INTERCHANGEABLE; they handle things differently according to the context.")
if (item.originalID == Player.PLAYER_REF_ID || item.originalID == 0x51621D) // do not delete this magic
throw IllegalArgumentException("Attempted to put human player into the inventory.")
if (Terrarum.ingame != null &&
(item.dynamicID == Terrarum.ingame?.player?.referenceID))
(item.originalID == Terrarum.ingame?.player?.referenceID))
throw IllegalArgumentException("Attempted to put active player into the inventory.")
if ((!item.stackable || item.dynamicID in ITEM_DYNAMIC) && count > 1)
throw IllegalArgumentException("Attempting to adding stack of item but the item is not stackable; item: $item, count: $count")
@@ -56,16 +67,16 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode
}
// new item
else {
if (item.isDynamic) {
/*if (item.isDynamic) {
// assign new ID for each
repeat(count) {
val newItem = item.clone().generateUniqueDynamicID(this)
itemList.add(InventoryPair(newItem, 1))
}
}
else {
else {*/
itemList.add(InventoryPair(item, count))
}
//}
}
insertionSortLastElem(itemList)
}
@@ -74,6 +85,17 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode
/** Will check existence of the item using its Dynamic ID; careful with command order!
* e.g. re-assign after this operation */
fun remove(item: InventoryItem, count: Int = 1) {
println("[ActorInventory] remove $item, $count")
if (count == 0)
throw IllegalArgumentException("Item count is zero.")
if (count < 0)
throw IllegalArgumentException("Item count is negative number. If you intended adding items, use add()" +
"These commands are NOT INTERCHANGEABLE; they handle things differently according to the context.")
val existingItem = getByDynamicID(item.dynamicID)
if (existingItem != null) { // if the item already exists
val newCount = getByDynamicID(item.dynamicID)!!.amount - count
@@ -82,7 +104,9 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode
}
else if (newCount > 0) {
// decrement count
add(item, -count)
val newCount = getByDynamicID(item.dynamicID)!!.amount - count
itemList.remove(existingItem)
itemList.add(InventoryPair(existingItem.item, newCount))
}
else {
// unequip, if applicable
@@ -139,16 +163,30 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode
fun consumeItem(actor: Actor, item: InventoryItem) {
if (item.consumable) {
if (item.stackable && !item.isDynamic) {
remove(item, 1)
}
else {
val newItem: InventoryItem
// unpack newly-made dynamic item (e.g. any weapon, floppy disk)
/*if (item.isDynamic && item.originalID == item.dynamicID) {
remove(item.originalID, 1)
item.generateUniqueDynamicID(this)
add(item)
}*/
if (item.isDynamic && item.originalID == item.dynamicID) {
itemEquipped[item.equipPosition] = null
remove(item, 1)
newItem = item.clone()
newItem.generateUniqueDynamicID(this)
newItem.stackable = false
add(newItem)
itemEquipped[newItem.equipPosition] = getByDynamicID(newItem.dynamicID)!!.item // will test if some sketchy code is written. Test fail: kotlinNullpointerException
// FIXME now damage meter (vital) is broken
}
else {
newItem = item
}
@@ -160,11 +198,11 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode
val swingDmgToFrameDmg = Terrarum.delta.toDouble() / actor.actorValue.getAsDouble(AVKey.ACTION_INTERVAL)!!
// damage the item
item.durability -= (baseDamagePerSwing * swingDmgToFrameDmg).toFloat()
if (item.durability <= 0)
remove(item, 1)
newItem.durability -= (baseDamagePerSwing * swingDmgToFrameDmg).toFloat()
if (newItem.durability <= 0)
remove(newItem, 1)
println("[ActorInventory] consumed; ${item.durability}")
//println("[ActorInventory] consumed; ${item.durability}")
}
}
@@ -179,12 +217,22 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode
if (itemList.size == 0)
false
else
itemList.binarySearch(id) >= 0
itemList.binarySearch(id, DYNAMIC_ID) >= 0
fun getByDynamicID(id: Int): InventoryPair? {
if (itemList.size == 0)
return null
val index = itemList.binarySearch(id)
val index = itemList.binarySearch(id, DYNAMIC_ID)
if (index < 0)
return null
else
return itemList[index]
}
private fun getByStaticID(id: Int): InventoryPair? {
if (itemList.size == 0)
return null
val index = itemList.binarySearch(id, STATIC_ID)
if (index < 0)
return null
else
@@ -201,7 +249,9 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode
arr[j + 1] = x
}
}
private fun ArrayList<InventoryPair>.binarySearch(ID: Int): Int {
private val STATIC_ID = 41324534
private val DYNAMIC_ID = 181643953
private fun ArrayList<InventoryPair>.binarySearch(ID: Int, searchBy: Int): Int {
// code from collections/Collections.kt
var low = 0
var high = this.size - 1
@@ -209,7 +259,7 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode
while (low <= high) {
val mid = (low + high).ushr(1) // safe from overflows
val midVal = get(mid).item.dynamicID
val midVal = if (searchBy == STATIC_ID) this.get(mid).item.originalID else this.get(mid).item.dynamicID
if (ID > midVal)
low = mid + 1

View File

@@ -57,7 +57,7 @@ open class HumanoidNPC(
}
override var inventoryCategory = "npc"
override val originalName: String = actorValue.getAsString(AVKey.NAME) ?: "NPC"
override var consumable = true
override var stackable = true
override val isDynamic = false
override fun secondaryUse(gc: GameContainer, delta: Int): Boolean {

View File

@@ -32,13 +32,16 @@ interface Pocketed {
* Equips an item. If the item is not in the inventory, adds the item first.
*/
fun equipItem(item: InventoryItem) {
if (!inventory.contains(item))
if (!inventory.contains(item)) {
println("[Pocketed] Item does not exist; adding one before equipped")
inventory.add(item)
}
if (item.equipPosition >= 0) {
inventory.itemEquipped[item.equipPosition] = item
item.effectWhenEquipped(Terrarum.appgc, Terrarum.delta)
}
// else do nothing
}
fun equipped(item: InventoryItem): Boolean {

View File

@@ -16,12 +16,15 @@ import org.newdawn.slick.GameContainer
abstract class InventoryItem : Comparable<InventoryItem>, Cloneable {
abstract var dynamicID: Int
/**
* if the ID is a Actor range, it's an actor contained in a pocket.
*/
abstract val originalID: Int // WUT?! using init does not work!!
/**
*
* e.g. Key Items (in a Pokémon sense), floppies
* e.g. Key Items (in a Pokémon sense); only the single instance of the item can exist in the pocket
*/
abstract val isUnique: Boolean
@@ -51,13 +54,15 @@ abstract class InventoryItem : Comparable<InventoryItem>, Cloneable {
var itemProperties = ItemValue()
/** Single-use then destroyed (e.g. Tiles), aka negation of "stackable" */
abstract var consumable: Boolean
/** Single-use then destroyed (e.g. Tiles), same as "consumable" */
abstract var stackable: Boolean
/**
* DYNAMIC means the item ID should be generated on the fly whenever the item is created.
* This is to be used with weapons/armours/etc where multiple instances can exist, and
* each of them should be treated as different item.
* each of them should be treated as different item. Because of this, new
* derivative instances (dynamically created items, e.g. used pickaxe) are not stackable.
*
* ID Range: 32768..1048575 (ItemCodex.ITEM_DYNAMIC)
*

View File

@@ -46,14 +46,14 @@ object ItemCodex {
// tile items (blocks and walls are the same thing basically)
for (i in ITEM_TILES + ITEM_WALLS) {
itemCodex[i] = object : InventoryItem() {
override var dynamicID: Int = i
override val originalID = dynamicID
override val originalID = i
override var dynamicID = i
override val isUnique: Boolean = false
override var baseMass: Double = TileCodex[i].density / 1000.0
override var baseToolSize: Double? = null
override var equipPosition = EquipPosition.HAND_GRIP
override val originalName = TileCodex[i % ITEM_WALLS.first].nameKey
override var consumable = true
override var stackable = true
override var inventoryCategory = Category.BLOCK
override var isDynamic = false
@@ -105,14 +105,14 @@ object ItemCodex {
// test copper pickaxe
itemCodex[ITEM_STATIC.first] = object : InventoryItem() {
override var dynamicID = ITEM_STATIC.first
override val originalID = dynamicID
override val originalID = ITEM_STATIC.first
override var dynamicID = originalID
override val isUnique = false
override val originalName = ""
override var baseMass = 10.0
override var baseToolSize: Double? = 10.0
override var consumable = false
override var maxDurability = 147//606 // this much tiles before breaking
override var stackable = true
override var maxDurability = 147//606
override var durability = maxDurability.toFloat()
override var equipPosition = EquipPosition.HAND_GRIP
override var inventoryCategory = Category.TOOL

View File

@@ -114,9 +114,9 @@ object Lang {
// special treatment
if (key.startsWith("MENU_LABEL_PRESS_START_SYMBOL"))
return ret2.replace('>', Terrarum.joypadLabelStart)
return ret2.replace('>', Terrarum.joypadLabelStart).capitalize()
return ret2
return ret2.capitalize()
}
fun pluraliseLang(key: String, count: Int): String {

View File

@@ -63,8 +63,8 @@ class UIInventory(
"MENU_LABEL_ALL",
"GAME_INVENTORY_BLOCKS",
"GAME_INVENTORY_WALLS",
"GAME_INVENTORY_WEAPONS", // weapons and tools
"CONTEXT_ITEM_TOOL_PLURAL",
"GAME_INVENTORY_WEAPONS",
"CONTEXT_ITEM_ARMOR",
"GAME_INVENTORY_INGREDIENTS",
"GAME_INVENTORY_POTIONS",
@@ -79,7 +79,7 @@ class UIInventory(
textAreaWidth = 100,
defaultSelection = 0,
iconSpriteSheet = SpriteSheet("./assets/graphics/gui/inventory/category.tga", 20, 20),
iconSpriteSheetIndices = intArrayOf(9,6,7,0,1,2,3,4,5,8),
iconSpriteSheetIndices = intArrayOf(9,6,7,1,0,2,3,4,5,8),
iconCol = defaultTextColour,
highlightBackCol = Color(0xb8b8b8),
highlightBackBlendMode = BlendMode.MULTIPLY,