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 5cd5ebbea3
commit c35ba8201a
10 changed files with 77 additions and 44 deletions

View File

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

View File

@@ -20,16 +20,16 @@ object AmmoMeterProxy {
else {
meter.vitalGetterVal = {
if (ItemCodex[currentItem.originalID].consumable)
actor.inventory.getByDynamicID(currentItem.dynamicID)!!.amount.toFloat()
else
actor.inventory.getByDynamicID(currentItem.dynamicID)!!.item.durability
actor.inventory.getByDynamicID(currentItem.dynamicID)!!.amount.toFloat()
else
currentItem.durability
}
meter.vitalGetterMax = {
if (ItemCodex[currentItem.originalID].consumable)
500f
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) {
g.font = Terrarum.fontGame
@@ -91,8 +93,8 @@ class UIItemInventoryElem(
// this one-liner sets color
g.color = item!!.nameColour mul if (mouseUp) mouseOverTextCol else inactiveTextCol
g.drawString(
"${item!!.dynamicID}/${item!!.originalID}" + (if (amount > 0 && !item!!.isUnique) "${0x3000.toChar()}($amount)" else "") +
//item!!.name + (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) "$fwsp($amount)" else "") +
(if (equippedSlot != null) " ${0xE081.toChar()}\$$equippedSlot" else ""),
posX + textOffsetX,
posY + textOffsetY

View File

@@ -39,7 +39,7 @@ internal object Inventory : ConsoleCommand {
if (it.amount == 0) {
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.Terrarum
import net.torvald.terrarum.itemproperties.ItemCodex
import net.torvald.terrarum.itemproperties.ItemCodex.ACTORID_MIN
import org.newdawn.slick.GameContainer
typealias ActorID = Int
@@ -22,6 +23,13 @@ abstract class Actor(val renderOrder: RenderOrder) : Comparable<Actor>, Runnable
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)
/**
@@ -52,18 +60,12 @@ abstract class Actor(val renderOrder: RenderOrder) : Comparable<Actor>, Runnable
fun hasCollision(value: ActorID) =
try {
Terrarum.ingame!!.theGameHasActor(value) ||
value < ItemCodex.ACTOR_ID_MIN ||
value < when (renderOrder) {
RenderOrder.BEHIND -> ItemCodex.ACTOR_ID_MIN
RenderOrder.MIDDLE -> 0x10000000
RenderOrder.MIDTOP -> 0x60000000
RenderOrder.FRONT -> 0x70000000
} ||
value > when (renderOrder) {
RenderOrder.BEHIND -> 0x0FFFFFFF
RenderOrder.MIDDLE -> 0x5FFFFFFF
RenderOrder.MIDTOP -> 0x6FFFFFFF
RenderOrder.FRONT -> 0x7FFFFFFF
value < ItemCodex.ACTORID_MIN ||
value !in when (renderOrder) {
RenderOrder.BEHIND -> RANGE_BEHIND
RenderOrder.MIDDLE -> RANGE_MIDDLE
RenderOrder.MIDTOP -> RANGE_MIDTOP
RenderOrder.FRONT -> RANGE_FRONT
}
}
catch (gameNotInitialisedException: KotlinNullPointerException) {

View File

@@ -57,18 +57,22 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode
// new item
else {
if (item.isDynamic) {
// assign new ID
println("[ActorInventory] new dynamic item detected: ${item.originalID}")
item.dynamicID = InventoryItem.generateNewDynamicID(this)
// assign new ID for each
repeat(count) {
val newItem = item.clone().generateUniqueDynamicID(this)
itemList.add(InventoryPair(newItem, 1))
}
}
else {
itemList.add(InventoryPair(item, count))
}
itemList.add(InventoryPair(item, count))
}
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) {
val existingItem = getByDynamicID(item.dynamicID)
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)
}
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)
actor.avStrength / 1000.0
else
1.0 // TODO variable: scale, strength
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)
@@ -194,11 +209,11 @@ 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
val midVal = get(mid).item.dynamicID
if (ID > midVal.dynamicID)
if (ID > midVal)
low = mid + 1
else if (ID < midVal.dynamicID)
else if (ID < midVal)
high = mid - 1
else
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) {
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.")
isVisible = true

View File

@@ -3,9 +3,12 @@ package net.torvald.terrarum.gameworld
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.
*
* 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.
*/
class GameEconomy {

View File

@@ -4,6 +4,7 @@ import net.torvald.random.HQRNG
import net.torvald.terrarum.ItemValue
import net.torvald.terrarum.gameactors.ActorInventory
import net.torvald.terrarum.gameactors.Pocketed
import net.torvald.terrarum.itemproperties.ItemCodex.ITEM_DYNAMIC
import net.torvald.terrarum.itemproperties.Material
import net.torvald.terrarum.langpack.Lang
import org.newdawn.slick.Color
@@ -111,7 +112,7 @@ abstract class InventoryItem : Comparable<InventoryItem>, Cloneable {
*/
open var durability: Float = 0f
var using = false
@Transient var using = false // Always false when loaded from savegame
/**
* Effects applied continuously while in pocket
@@ -166,7 +167,7 @@ abstract class InventoryItem : Comparable<InventoryItem>, Cloneable {
override fun toString(): String {
return dynamicID.toString()
return "$dynamicID/$originalID"
}
override fun hashCode(): Int {
@@ -242,13 +243,23 @@ abstract class InventoryItem : Comparable<InventoryItem>, Cloneable {
return clonedItem
}
fun generateUniqueDynamicID(inventory: ActorInventory): InventoryItem {
dynamicID = InventoryItem.generateUniqueDynamicID(inventory)
return this
}
companion object {
fun generateNewDynamicID(inventory: ActorInventory): Int {
fun generateUniqueDynamicID(inventory: ActorInventory): Int {
var ret: Int
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))
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>
* Will return corresponding Actor if ID >= 16777216
* Will return corresponding Actor if ID >= ACTORID_MIN
*/
private val itemCodex = HashMap<Int, InventoryItem>()
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_WIRES = GameWorld.TILES_SUPPORTED * 2..GameWorld.TILES_SUPPORTED * 2 + 255
val ITEM_STATIC = ITEM_WIRES.endInclusive + 1..32767
val ITEM_DYNAMIC = 32768..1048575
val ACTOR_ID_MIN = ITEM_DYNAMIC.endInclusive + 1
val ITEM_DYNAMIC = 32768..0x0FFF_FFFF
val ACTORID_MIN = ITEM_DYNAMIC.endInclusive + 1
private val itemImagePlaceholder = Image("./assets/item_kari_24.tga")