mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 20:31:51 +09:00
fresh-new dynamic items (e.g. pickaxe) can be stacked
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
})
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user