mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-11 02:54:04 +09:00
new ID for dynamic item work flawlessly with adding multiple at once
This commit is contained in:
@@ -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)
|
||||||
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 ""}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
Reference in New Issue
Block a user