new ID for dynamic item work flawlessly with adding multiple at once

This commit is contained in:
Song Minjae
2017-04-24 21:31:53 +09:00
parent d70cb2524d
commit a72b6f0d1a
10 changed files with 77 additions and 44 deletions

View File

@@ -4,9 +4,9 @@
|4096..8191|Walls| |4096..8191|Walls|
|8192..8447|Wires| |8192..8447|Wires|
|8448..32767|Items (static)| |8448..32767|Items (static)|
|32768..1048575|Items (dynamic\*)| |32768..0x0FFF_FFFF|Items (dynamic\*)|
|1048576..0x7FFF_FFFF|Actors| |0x1000_0000..0x7FFF_FFFF|Actors|
|0x8000_0000..0xFFFF_FFFF (all negative numbers)|Faction| |-2147483648..-1 (all negative numbers)|Faction|
* dynamic items can have their own properties that will persist through savegame. * dynamic items can have their own properties that will persist through savegame.
@@ -14,7 +14,7 @@ Actors range in-depth
|Range|Description| |Range|Description|
|-----|-----------| |-----|-----------|
|1048576..0x0FFF_FFFF|Rendered behind (e.g. tapestries) |0x1000_0000..0x1FFF_FFFF|Rendered behind (e.g. tapestries)
|0x1000_0000..0x5FFF_FFFF|Regular actors (e.g. almost all of them) |0x2000_0000..0x5FFF_FFFF|Regular actors (e.g. almost all of them)
|0x6000_0000..0x6FFF_FFFF|Special (e.g. weapon swung, bullets, dropped item, particles) |0x6000_0000..0x6FFF_FFFF|Special (e.g. weapon swung, bullets, dropped item, particles)
|0x7000_0000..0x7FFF_FFFF|Rendered front (e.g. fake tile) |0x7000_0000..0x7FFF_FFFF|Rendered front (e.g. fake tile)

View File

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

View File

@@ -62,6 +62,8 @@ class UIItemInventoryElem(
} }
} }
private val fwsp = 0x3000.toChar()
override fun render(gc: GameContainer, g: Graphics) { override fun render(gc: GameContainer, g: Graphics) {
g.font = Terrarum.fontGame g.font = Terrarum.fontGame
@@ -91,8 +93,8 @@ class UIItemInventoryElem(
// this one-liner sets color // this one-liner sets color
g.color = item!!.nameColour mul if (mouseUp) mouseOverTextCol else inactiveTextCol g.color = item!!.nameColour mul if (mouseUp) mouseOverTextCol else inactiveTextCol
g.drawString( g.drawString(
"${item!!.dynamicID}/${item!!.originalID}" + (if (amount > 0 && !item!!.isUnique) "${0x3000.toChar()}($amount)" else "") + "$item" + (if (amount > 0 && !item!!.isUnique) "$fwsp($amount)" else "") +
//item!!.name + (if (amount > 0 && !item!!.isUnique) "${0x3000.toChar()}($amount)" else "") + //item!!.name + (if (amount > 0 && !item!!.isUnique) "$fwsp($amount)" else "") +
(if (equippedSlot != null) " ${0xE081.toChar()}\$$equippedSlot" else ""), (if (equippedSlot != null) " ${0xE081.toChar()}\$$equippedSlot" else ""),
posX + textOffsetX, posX + textOffsetX,
posY + textOffsetY posY + textOffsetY

View File

@@ -39,7 +39,7 @@ internal object Inventory : ConsoleCommand {
if (it.amount == 0) { if (it.amount == 0) {
EchoError("Unexpected zero-amounted item: ID ${it.item.dynamicID}") EchoError("Unexpected zero-amounted item: ID ${it.item.dynamicID}")
} }
Echo("ID ${it.item.dynamicID}${if (it.amount > 1) " ($it.second)" else ""}") Echo("ID ${it.item}${if (it.amount > 1) " (${it.amount})" else ""}")
} }
} }
} }

View File

@@ -4,6 +4,7 @@ import net.torvald.random.HQRNG
import net.torvald.terrarum.ActorValue import net.torvald.terrarum.ActorValue
import net.torvald.terrarum.Terrarum import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.itemproperties.ItemCodex import net.torvald.terrarum.itemproperties.ItemCodex
import net.torvald.terrarum.itemproperties.ItemCodex.ACTORID_MIN
import org.newdawn.slick.GameContainer import org.newdawn.slick.GameContainer
typealias ActorID = Int typealias ActorID = Int
@@ -22,6 +23,13 @@ abstract class Actor(val renderOrder: RenderOrder) : Comparable<Actor>, Runnable
FRONT // fake tiles FRONT // fake tiles
} }
companion object {
val RANGE_BEHIND = ACTORID_MIN..0x1FFF_FFFF
val RANGE_MIDDLE = 0x2000_0000..0x5FFF_FFFF
val RANGE_MIDTOP = 0x6000_0000..0x6FFF_FFFF
val RANGE_FRONT = 0x7000_0000..0x7FFF_FFFF
}
abstract fun update(gc: GameContainer, delta: Int) abstract fun update(gc: GameContainer, delta: Int)
/** /**
@@ -52,18 +60,12 @@ abstract class Actor(val renderOrder: RenderOrder) : Comparable<Actor>, Runnable
fun hasCollision(value: ActorID) = fun hasCollision(value: ActorID) =
try { try {
Terrarum.ingame!!.theGameHasActor(value) || Terrarum.ingame!!.theGameHasActor(value) ||
value < ItemCodex.ACTOR_ID_MIN || value < ItemCodex.ACTORID_MIN ||
value < when (renderOrder) { value !in when (renderOrder) {
RenderOrder.BEHIND -> ItemCodex.ACTOR_ID_MIN RenderOrder.BEHIND -> RANGE_BEHIND
RenderOrder.MIDDLE -> 0x10000000 RenderOrder.MIDDLE -> RANGE_MIDDLE
RenderOrder.MIDTOP -> 0x60000000 RenderOrder.MIDTOP -> RANGE_MIDTOP
RenderOrder.FRONT -> 0x70000000 RenderOrder.FRONT -> RANGE_FRONT
} ||
value > when (renderOrder) {
RenderOrder.BEHIND -> 0x0FFFFFFF
RenderOrder.MIDDLE -> 0x5FFFFFFF
RenderOrder.MIDTOP -> 0x6FFFFFFF
RenderOrder.FRONT -> 0x7FFFFFFF
} }
} }
catch (gameNotInitialisedException: KotlinNullPointerException) { catch (gameNotInitialisedException: KotlinNullPointerException) {

View File

@@ -57,18 +57,22 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode
// new item // new item
else { else {
if (item.isDynamic) { if (item.isDynamic) {
// assign new ID // assign new ID for each
repeat(count) {
println("[ActorInventory] new dynamic item detected: ${item.originalID}") val newItem = item.clone().generateUniqueDynamicID(this)
itemList.add(InventoryPair(newItem, 1))
item.dynamicID = InventoryItem.generateNewDynamicID(this) }
}
else {
itemList.add(InventoryPair(item, count))
} }
itemList.add(InventoryPair(item, count))
} }
insertionSortLastElem(itemList) insertionSortLastElem(itemList)
} }
fun remove(itemID: Int, count: Int = 1) = remove(ItemCodex[itemID], count) fun remove(itemID: Int, count: Int) = remove(ItemCodex[itemID], count)
/** 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) { fun remove(item: InventoryItem, count: Int = 1) {
val existingItem = getByDynamicID(item.dynamicID) val existingItem = getByDynamicID(item.dynamicID)
if (existingItem != null) { // if the item already exists if (existingItem != null) { // if the item already exists
@@ -139,12 +143,23 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode
remove(item, 1) remove(item, 1)
} }
else { else {
// 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)
}*/
// calculate damage value
val baseDamagePerSwing = if (actor is ActorHumanoid) val baseDamagePerSwing = if (actor is ActorHumanoid)
actor.avStrength / 1000.0 actor.avStrength / 1000.0
else else
1.0 // TODO variable: scale, strength 1.0 // TODO variable: scale, strength
val swingDmgToFrameDmg = Terrarum.delta.toDouble() / actor.actorValue.getAsDouble(AVKey.ACTION_INTERVAL)!! val swingDmgToFrameDmg = Terrarum.delta.toDouble() / actor.actorValue.getAsDouble(AVKey.ACTION_INTERVAL)!!
// damage the item
item.durability -= (baseDamagePerSwing * swingDmgToFrameDmg).toFloat() item.durability -= (baseDamagePerSwing * swingDmgToFrameDmg).toFloat()
if (item.durability <= 0) if (item.durability <= 0)
remove(item, 1) remove(item, 1)
@@ -194,11 +209,11 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode
while (low <= high) { while (low <= high) {
val mid = (low + high).ushr(1) // safe from overflows val mid = (low + high).ushr(1) // safe from overflows
val midVal = get(mid).item val midVal = get(mid).item.dynamicID
if (ID > midVal.dynamicID) if (ID > midVal)
low = mid + 1 low = mid + 1
else if (ID < midVal.dynamicID) else if (ID < midVal)
high = mid - 1 high = mid - 1
else else
return mid // key found return mid // key found

View File

@@ -12,7 +12,7 @@ import org.newdawn.slick.Graphics
class DroppedItem(private val item: InventoryItem) : ActorWithPhysics(Actor.RenderOrder.MIDTOP) { class DroppedItem(private val item: InventoryItem) : ActorWithPhysics(Actor.RenderOrder.MIDTOP) {
init { init {
if (item.dynamicID >= ItemCodex.ACTOR_ID_MIN) if (item.dynamicID >= ItemCodex.ACTORID_MIN)
throw RuntimeException("Attempted to create DroppedItem actor of a real actor; the real actor must be dropped instead.") throw RuntimeException("Attempted to create DroppedItem actor of a real actor; the real actor must be dropped instead.")
isVisible = true isVisible = true

View File

@@ -3,9 +3,12 @@ package net.torvald.terrarum.gameworld
import net.torvald.terrarum.gameactors.ActorID import net.torvald.terrarum.gameactors.ActorID
/** /**
* This world is economically isolated system. Economy will be important to make player keep playing, * The whole world is economically isolated system. Economy will be important to make player keep playing,
* when all the necessary contents are set and implemented to the production. * when all the necessary contents are set and implemented to the production.
* *
* Design goal: keep the inflation rate low, but not negative (Single market)
* OR, give each faction (establishment) its own economy and watch them prosper/doomed (DF style)
*
* Created by SKYHi14 on 2017-04-23. * Created by SKYHi14 on 2017-04-23.
*/ */
class GameEconomy { class GameEconomy {

View File

@@ -4,6 +4,7 @@ import net.torvald.random.HQRNG
import net.torvald.terrarum.ItemValue import net.torvald.terrarum.ItemValue
import net.torvald.terrarum.gameactors.ActorInventory import net.torvald.terrarum.gameactors.ActorInventory
import net.torvald.terrarum.gameactors.Pocketed import net.torvald.terrarum.gameactors.Pocketed
import net.torvald.terrarum.itemproperties.ItemCodex.ITEM_DYNAMIC
import net.torvald.terrarum.itemproperties.Material import net.torvald.terrarum.itemproperties.Material
import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.langpack.Lang
import org.newdawn.slick.Color import org.newdawn.slick.Color
@@ -111,7 +112,7 @@ abstract class InventoryItem : Comparable<InventoryItem>, Cloneable {
*/ */
open var durability: Float = 0f open var durability: Float = 0f
var using = false @Transient var using = false // Always false when loaded from savegame
/** /**
* Effects applied continuously while in pocket * Effects applied continuously while in pocket
@@ -166,7 +167,7 @@ abstract class InventoryItem : Comparable<InventoryItem>, Cloneable {
override fun toString(): String { override fun toString(): String {
return dynamicID.toString() return "$dynamicID/$originalID"
} }
override fun hashCode(): Int { override fun hashCode(): Int {
@@ -242,13 +243,23 @@ abstract class InventoryItem : Comparable<InventoryItem>, Cloneable {
return clonedItem return clonedItem
} }
fun generateUniqueDynamicID(inventory: ActorInventory): InventoryItem {
dynamicID = InventoryItem.generateUniqueDynamicID(inventory)
return this
}
companion object { companion object {
fun generateNewDynamicID(inventory: ActorInventory): Int { fun generateUniqueDynamicID(inventory: ActorInventory): Int {
var ret: Int var ret: Int
do { do {
ret = HQRNG().nextInt(ItemCodex.ITEM_DYNAMIC.endInclusive + 1 - ItemCodex.ITEM_DYNAMIC.first) + ItemCodex.ITEM_DYNAMIC.first ret = ITEM_DYNAMIC.pickRandom()
} while (inventory.contains(ret)) } while (inventory.contains(ret))
return ret return ret
} }
} }
} }
fun IntRange.pickRandom() = HQRNG().nextInt(this.endInclusive - this.start + 1) + this.start // count() on 200 million entries? Se on vitun hyvää idea
fun IntArray.pickRandom(): Int = this[HQRNG().nextInt(this.size)]
fun DoubleArray.pickRandom(): Double = this[HQRNG().nextInt(this.size)]

View File

@@ -26,7 +26,7 @@ object ItemCodex {
/** /**
* <ItemID or RefID for Actor, TheItem> * <ItemID or RefID for Actor, TheItem>
* Will return corresponding Actor if ID >= 16777216 * Will return corresponding Actor if ID >= ACTORID_MIN
*/ */
private val itemCodex = HashMap<Int, InventoryItem>() private val itemCodex = HashMap<Int, InventoryItem>()
private val dynamicItemDescription = HashMap<Int, KVHashMap>() private val dynamicItemDescription = HashMap<Int, KVHashMap>()
@@ -35,8 +35,8 @@ object ItemCodex {
val ITEM_WALLS = GameWorld.TILES_SUPPORTED..GameWorld.TILES_SUPPORTED * 2 - 1 val ITEM_WALLS = GameWorld.TILES_SUPPORTED..GameWorld.TILES_SUPPORTED * 2 - 1
val ITEM_WIRES = GameWorld.TILES_SUPPORTED * 2..GameWorld.TILES_SUPPORTED * 2 + 255 val ITEM_WIRES = GameWorld.TILES_SUPPORTED * 2..GameWorld.TILES_SUPPORTED * 2 + 255
val ITEM_STATIC = ITEM_WIRES.endInclusive + 1..32767 val ITEM_STATIC = ITEM_WIRES.endInclusive + 1..32767
val ITEM_DYNAMIC = 32768..1048575 val ITEM_DYNAMIC = 32768..0x0FFF_FFFF
val ACTOR_ID_MIN = ITEM_DYNAMIC.endInclusive + 1 val ACTORID_MIN = ITEM_DYNAMIC.endInclusive + 1
private val itemImagePlaceholder = Image("./assets/item_kari_24.tga") private val itemImagePlaceholder = Image("./assets/item_kari_24.tga")