diff --git a/assets/locales/koKR/game.json b/assets/locales/koKR/game.json index fb603a837..54feec9b0 100644 --- a/assets/locales/koKR/game.json +++ b/assets/locales/koKR/game.json @@ -13,5 +13,5 @@ "GAME_INVENTORY_BLOCKS" : "블록", "GAME_INVENTORY_WALLS" : "벽지", "CONTEXT_ITEM_EQUIPMENT_PLURAL" : "장비", - "GAME_INVENTORY_FAVORITES" : "중요" + "GAME_INVENTORY_FAVORITES" : "등록" } \ No newline at end of file diff --git a/lib/kotlin-reflect.jar b/lib/kotlin-reflect.jar index a25e7b3ef..896a39362 100755 Binary files a/lib/kotlin-reflect.jar and b/lib/kotlin-reflect.jar differ diff --git a/lib/kotlin-runtime-sources.jar b/lib/kotlin-runtime-sources.jar index d96e8c065..31c6f0997 100755 Binary files a/lib/kotlin-runtime-sources.jar and b/lib/kotlin-runtime-sources.jar differ diff --git a/lib/kotlin-runtime.jar b/lib/kotlin-runtime.jar index b58cc6993..0ec4ec7b3 100755 Binary files a/lib/kotlin-runtime.jar and b/lib/kotlin-runtime.jar differ diff --git a/src/net/torvald/terrarum/StateControllerRumbleTest.kt b/src/net/torvald/terrarum/StateControllerRumbleTest.kt new file mode 100644 index 000000000..e05decb58 --- /dev/null +++ b/src/net/torvald/terrarum/StateControllerRumbleTest.kt @@ -0,0 +1,55 @@ +package net.torvald.terrarum + +import net.torvald.terrarum.gamecontroller.Key +import net.torvald.terrarum.gamecontroller.KeyToggler +import net.torvald.terrarum.gameworld.fmod +import org.newdawn.slick.Color +import org.newdawn.slick.GameContainer +import org.newdawn.slick.Graphics +import org.newdawn.slick.state.BasicGameState +import org.newdawn.slick.state.StateBasedGame + +/** + * Created by SKYHi14 on 2017-03-15. + */ +class StateControllerRumbleTest : BasicGameState() { + override fun init(container: GameContainer?, game: StateBasedGame?) { + } + + override fun update(container: GameContainer, game: StateBasedGame, delta: Int) { + Terrarum.appgc.setTitle("${GAME_NAME} — Do not pull out the controller!") + + KeyToggler.update(container.input) + + if (Terrarum.controller != null) { + for (i in 0..minOf(rumblerCount - 1, 9)) { + Terrarum.controller!!.setRumblerStrength(i, if (KeyToggler.isOn(2 + i)) 1f else 0f) + } + } + } + + private var rumblerCount = Terrarum.controller?.rumblerCount ?: 0 + + override fun getID() = Terrarum.STATE_ID_TOOL_RUMBLE_DIAGNOSIS + + override fun render(gc: GameContainer, game: StateBasedGame, g: Graphics) { + g.font = Terrarum.fontGame + g.color = Color.white + + if (Terrarum.controller != null) { + g.drawString("Controller: ${Terrarum.controller!!.name}", 10f, 10f) + g.drawString("Rumbler count: ${rumblerCount}", 10f, 30f) + g.drawString("Rumblers", 10f, 70f) + for (i in 0..minOf(rumblerCount - 1, 9)) { + g.color = if (KeyToggler.isOn(2 + i)) Color(0x55ff55) else Color(0x808080) + //g.drawString("$i", 10f + i * 16f, 90f) + + g.drawString("$i — ${Terrarum.controller!!.getRumblerName(i)}", 10f, 90f + 20 * i) + } + } + else { + g.drawString("Controller not found.", 10f, 10f) + } + } + +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/StateUITest.kt b/src/net/torvald/terrarum/StateUITest.kt index 0599647ca..bd1800d79 100644 --- a/src/net/torvald/terrarum/StateUITest.kt +++ b/src/net/torvald/terrarum/StateUITest.kt @@ -1,16 +1,14 @@ package net.torvald.terrarum import net.torvald.terrarum.gameactors.ActorInventory +import net.torvald.terrarum.gameactors.InventoryPair import net.torvald.terrarum.gameitem.InventoryItem import net.torvald.terrarum.mapdrawer.MapCamera import net.torvald.terrarum.ui.UICanvas import net.torvald.terrarum.ui.UIHandler import net.torvald.terrarum.ui.UIItemTextButton import net.torvald.terrarum.ui.UIItemTextButtonList -import org.newdawn.slick.Color -import org.newdawn.slick.GameContainer -import org.newdawn.slick.Graphics -import org.newdawn.slick.Input +import org.newdawn.slick.* import org.newdawn.slick.state.BasicGameState import org.newdawn.slick.state.StateBasedGame @@ -19,11 +17,13 @@ import org.newdawn.slick.state.StateBasedGame */ class StateUITest : BasicGameState() { - val ui = UIHandler(SimpleUI()) + val ui: UIHandler val inventory = ActorInventory() init { + ui = UIHandler(SimpleUI(inventory)) + ui.posX = 50 ui.posY = 30 ui.isVisible = true @@ -31,13 +31,18 @@ class StateUITest : BasicGameState() { inventory.add(object : InventoryItem() { override val id: Int = 5656 + override var originalName: String = "Test tool" override var baseMass: Double = 12.0 override var baseToolSize: Double? = 8.0 override var category: String = "tool" + override var maxDurability: Double = 10.0 + override var durability: Double = 10.0 }) + inventory.getByID(5656)!!.item.name = "Test tool" inventory.add(object : InventoryItem() { override val id: Int = 4633 + override var originalName: String = "CONTEXT_ITEM_QUEST_NOUN" override var baseMass: Double = 1.4 override var baseToolSize: Double? = null override var category: String = "bulk" @@ -64,12 +69,14 @@ class StateUITest : BasicGameState() { -private class SimpleUI : UICanvas { +private class SimpleUI(val inventory: ActorInventory) : UICanvas { override var width = 700 - override var height = 440 // multiple of 40 (2 * font.lineHeight) + override var height = 480 // multiple of 40 (2 * font.lineHeight) override var handler: UIHandler? = null override var openCloseTime: Int = UICanvas.OPENCLOSE_GENERIC + val itemImage = Image("./assets/item_kari_24.tga") + val buttons = UIItemTextButtonList( this, arrayOf( @@ -93,10 +100,48 @@ private class SimpleUI : UICanvas { kinematic = true ) + val itemStripGutterV = 4 + val itemStripGutterH = 48 + + val itemsStripWidth = width - buttons.width - 2 * itemStripGutterH + val items = Array(height / (UIItemInventoryElem.height + itemStripGutterV), { UIItemInventoryElem( + parentUI = this, + posX = buttons.width + itemStripGutterH, + posY = it * (UIItemInventoryElem.height + itemStripGutterV), + width = itemsStripWidth, + item = null, + amount = UIItemInventoryElem.UNIQUE_ITEM_HAS_NO_AMOUNT, + itemImage = null, + backCol = Color(255, 255, 255, 0x30) + ) }) + val itemsScrollOffset = 0 + + var inventorySortList = ArrayList() + var rebuildList = true + override fun update(gc: GameContainer, delta: Int) { - Terrarum.gameLocale = "fiFI" // hot swap this to test + Terrarum.gameLocale = "en" // hot swap this to test buttons.update(gc, delta) + + + // test fill: just copy the inventory, fuck sorting + if (rebuildList) { + inventorySortList = ArrayList() + inventory.forEach { inventorySortList.add(it) } + rebuildList = false + + // sort if needed // + + inventorySortList.forEachIndexed { index, pair -> + if (index - itemsScrollOffset >= 0 && index < items.size + itemsScrollOffset) { + items[index - itemsScrollOffset].item = pair.item + items[index - itemsScrollOffset].amount = pair.amount + items[index - itemsScrollOffset].itemImage = itemImage + } + } + } + } override fun render(gc: GameContainer, g: Graphics) { @@ -104,6 +149,11 @@ private class SimpleUI : UICanvas { g.fillRect(0f, 0f, width.toFloat(), height.toFloat()) buttons.render(gc, g) + + + items.forEach { + it.render(gc, g) + } } override fun processInput(gc: GameContainer, delta: Int, input: Input) { @@ -121,7 +171,7 @@ private class SimpleUI : UICanvas { UICanvas.endOpeningFade(handler) } - override fun endClosing(gc: GameContainer, delta: Int) { + override fun endClosing(gc: GameContainer, delta: Int) {7 UICanvas.endClosingFade(handler) } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index c2b3368d7..c1adc645e 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -138,6 +138,7 @@ object Terrarum : StateBasedGame(GAME_NAME) { val STATE_ID_TEST_UI = 0x105 val STATE_ID_TOOL_NOISEGEN = 0x200 + val STATE_ID_TOOL_RUMBLE_DIAGNOSIS = 0x201 var controller: org.lwjgl.input.Controller? = null private set @@ -284,9 +285,9 @@ object Terrarum : StateBasedGame(GAME_NAME) { //addState(StateShaderTest()) //addState(StateNoiseTester()) addState(StateUITest()) + //addState(StateControllerRumbleTest()) - //ingame = StateInGame() - //addState(ingame) + //ingame = StateInGame(); addState(ingame) // foolproof diff --git a/src/net/torvald/terrarum/UIItemInventoryElem.kt b/src/net/torvald/terrarum/UIItemInventoryElem.kt new file mode 100644 index 000000000..69324a542 --- /dev/null +++ b/src/net/torvald/terrarum/UIItemInventoryElem.kt @@ -0,0 +1,101 @@ +package net.torvald.terrarum + +import net.torvald.terrarum.gameitem.InventoryItem +import net.torvald.terrarum.ui.UICanvas +import net.torvald.terrarum.ui.UIItem +import net.torvald.terrarum.ui.UIItemTextButton +import org.newdawn.slick.Color +import org.newdawn.slick.GameContainer +import org.newdawn.slick.Graphics +import org.newdawn.slick.Image + +/** + * @param amount: set to -1 (UIItemInventoryElem.UNIQUE_ITEM_HAS_NO_AMOUNT) for unique item (does not show item count) + * + * Note that the UI will not render if either item or itemImage is null. + * + * Created by SKYHi14 on 2017-03-16. + */ +class UIItemInventoryElem( + parentUI: UICanvas, + override var posX: Int, + override var posY: Int, + override val width: Int, + var item: InventoryItem?, + var amount: Int, + var itemImage: Image?, + val backCol: Color = Color(0,0,0,0), + val backColBlendMode: String = BlendMode.NORMAL +) : UIItem(parentUI) { + + companion object { + val height = 48 + val UNIQUE_ITEM_HAS_NO_AMOUNT = -1 + } + + override val height = UIItemInventoryElem.height + + private val imgOffset: Float + get() = (this.height - itemImage!!.height).div(2).toFloat() // to snap to the pixel grid + private val textOffsetX = 52f + + override fun update(gc: GameContainer, delta: Int) { + if (item != null) { + + } + } + + override fun render(gc: GameContainer, g: Graphics) { + if (item != null && itemImage != null) { + g.font = Terrarum.fontGame + + + if (mouseUp) { + BlendMode.resolve(backColBlendMode) + g.color = backCol + g.fillRect(posX.toFloat(), posY.toFloat(), width.toFloat(), height.toFloat()) + } + + + blendNormal() + + g.drawImage(itemImage!!, posX + imgOffset, posY + imgOffset) + + // if mouse is over, text lights up + g.color = item!!.nameColour * if (mouseUp) Color(0xffffff) else UIItemTextButton.defaultInactiveCol + g.drawString(item!!.name, posX + textOffsetX, posY + 0f) + + + if (item!!.maxDurability > 0.0) { + // TODO durability gauge + } + } + } + + override fun keyPressed(key: Int, c: Char) { + } + + override fun keyReleased(key: Int, c: Char) { + } + + override fun mouseMoved(oldx: Int, oldy: Int, newx: Int, newy: Int) { + } + + override fun mouseDragged(oldx: Int, oldy: Int, newx: Int, newy: Int) { + } + + override fun mousePressed(button: Int, x: Int, y: Int) { + } + + override fun mouseReleased(button: Int, x: Int, y: Int) { + } + + override fun mouseWheelMoved(change: Int) { + } + + override fun controllerButtonPressed(controller: Int, button: Int) { + } + + override fun controllerButtonReleased(controller: Int, button: Int) { + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/console/Inventory.kt b/src/net/torvald/terrarum/console/Inventory.kt index 14ecaa59d..3678773de 100644 --- a/src/net/torvald/terrarum/console/Inventory.kt +++ b/src/net/torvald/terrarum/console/Inventory.kt @@ -35,11 +35,11 @@ internal object Inventory : ConsoleCommand { Echo("(inventory empty)") } else { - target.inventory.forEach { refId, amount -> - if (amount == 0) { - EchoError("Unexpected zero-amounted item: ID $refId") + target.inventory.forEach { + if (it.amount == 0) { + EchoError("Unexpected zero-amounted item: ID ${it.item.id}") } - Echo("ID $refId${if (amount > 1) " ($amount)" else ""}") + Echo("ID ${it.item.id}${if (it.amount > 1) " ($it.second)" else ""}") } } } @@ -62,7 +62,7 @@ internal object Inventory : ConsoleCommand { val item = ItemCodex[refId] // if the item does not exist, add it first - if (!target.inventory.contains(item)) { + if (!target.inventory.hasItem(item)) { target.inventory.add(item) } diff --git a/src/net/torvald/terrarum/gameactors/ActorHumanoid.kt b/src/net/torvald/terrarum/gameactors/ActorHumanoid.kt index cd4774b88..12599d6d9 100644 --- a/src/net/torvald/terrarum/gameactors/ActorHumanoid.kt +++ b/src/net/torvald/terrarum/gameactors/ActorHumanoid.kt @@ -140,6 +140,7 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null) override var baseMass: Double = 0.0 override var baseToolSize: Double? = null override var category = "should_not_be_seen" + override val originalName: String = actorValue.getAsString(AVKey.NAME) ?: "(no name)" } override fun update(gc: GameContainer, delta: Int) { @@ -168,12 +169,12 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null) } // update inventory items - inventory.forEach { item, amount -> - if (!itemEquipped.contains(item)) { // unequipped - item.effectWhileInPocket(gc, delta) + inventory.forEach { + if (!itemEquipped.contains(it.item)) { // unequipped + it.item.effectWhileInPocket(gc, delta) } else { // equipped - item.effectWhenEquipped(gc, delta) + it.item.effectWhenEquipped(gc, delta) } } } diff --git a/src/net/torvald/terrarum/gameactors/ActorInventory.kt b/src/net/torvald/terrarum/gameactors/ActorInventory.kt index d3c3f6170..6dedc51cb 100644 --- a/src/net/torvald/terrarum/gameactors/ActorInventory.kt +++ b/src/net/torvald/terrarum/gameactors/ActorInventory.kt @@ -4,6 +4,8 @@ import net.torvald.terrarum.Terrarum import net.torvald.terrarum.gameitem.InventoryItem import net.torvald.terrarum.itemproperties.ItemCodex import java.util.* +import java.util.concurrent.locks.Lock +import java.util.concurrent.locks.ReentrantLock /** * Created by minjaesong on 16-03-15. @@ -22,9 +24,9 @@ class ActorInventory() { private var capacityMode: Int /** - * HashMap + * Sorted by referenceID. */ - private val itemList: HashMap = HashMap() + private val itemList = ArrayList() /** * Default constructor with no encumbrance. @@ -62,32 +64,42 @@ class ActorInventory() { // If we already have the item, increment the amount // If not, add item with specified amount - itemList.put(item, itemList[item] ?: 0 + count) + val existingItem = getByID(item.id) + if (existingItem != null) { // if the item already exists + val newCount = getByID(item.id)!!.amount + count + itemList.remove(existingItem) + itemList.add(InventoryPair(existingItem.item, newCount)) + } + else { + itemList.add(InventoryPair(item, count)) + } + insertionSortLastElem(itemList) } fun remove(itemID: Int, count: Int = 1) = remove(ItemCodex[itemID], count) fun remove(item: InventoryItem, count: Int = 1) { - // check if the item does NOT exist - if (itemList[item] == null) { - return + val existingItem = getByID(item.id) + if (existingItem != null) { // if the item already exists + val newCount = getByID(item.id)!!.amount - count + if (newCount < 0) { + throw Error("Tried to remove $count of $item, but the inventory only contains ${getByID(item.id)!!.amount} of them.") + } + else if (newCount > 0) { + add(item, -count) + } + else { + itemList.remove(existingItem) + } } else { - // remove the existence of the item if count <= 0 - if (itemList[item]!! - count <= 0) { - itemList.remove(item) - } - // else, decrement the item count - else { - itemList.put(item, itemList[item]!! - count) - } + throw Error("Tried to remove $item, but the inventory does not have it.") } } - - fun contains(item: InventoryItem) = itemList.containsKey(item) - fun contains(itemID: Int) = itemList.containsKey(ItemCodex[itemID]) - - fun forEach(consumer: (InventoryItem, Int) -> Unit) = itemList.forEach(consumer) + /** + * HashMap + */ + fun forEach(consumer: (InventoryPair) -> Unit) = itemList.forEach(consumer) /** * Get capacity of inventory @@ -109,26 +121,9 @@ class ActorInventory() { return capacityMode } - /** - * Get reference to the itemList - * @return - */ - fun getItemList(): Map? { - return itemList - } - - /** - * Get clone of the itemList - * @return - */ - @Suppress("UNCHECKED_CAST") - fun getCopyOfItemList(): Map? { - return itemList.clone() as Map - } - fun getTotalWeight(): Double { var weight = 0.0 - itemList.forEach { item, i -> weight += item.mass * i } + itemList.forEach { weight += it.item.mass * it.amount } return weight } @@ -138,7 +133,7 @@ class ActorInventory() { */ fun getTotalCount(): Int { var count = 0 - itemList.forEach { item, i -> count += i } + itemList.forEach { count += it.amount } return count } @@ -158,10 +153,72 @@ class ActorInventory() { if (getCapacityMode() == CAPACITY_MODE_WEIGHT) { return capacityByWeight < getTotalWeight() } else if (getCapacityMode() == CAPACITY_MODE_COUNT) { - return capacityByCount < getTotalWeight() + return capacityByCount < getTotalCount() } else { return false } } -} \ No newline at end of file + + + + + + fun hasItem(item: InventoryItem) = hasItem(item.id) + fun hasItem(id: Int) = + if (itemList.size == 0) + false + else + itemList.binarySearch(id) >= 0 + fun getByID(id: Int): InventoryPair? { + if (itemList.size == 0) + return null + + val index = itemList.binarySearch(id) + if (index < 0) + return null + else + return itemList[index] + } + private fun insertionSortLastElem(arr: ArrayList) { + lock(ReentrantLock()) { + var j = arr.lastIndex - 1 + val x = arr.last() + while (j >= 0 && arr[j].item > x.item) { + arr[j + 1] = arr[j] + j -= 1 + } + arr[j + 1] = x + } + } + private fun ArrayList.binarySearch(ID: Int): Int { + // code from collections/Collections.kt + var low = 0 + var high = this.size - 1 + + while (low <= high) { + val mid = (low + high).ushr(1) // safe from overflows + + val midVal = get(mid).item + + if (ID > midVal.id) + low = mid + 1 + else if (ID < midVal.id) + high = mid - 1 + else + return mid // key found + } + return -(low + 1) // key not found + } + inline fun lock(lock: Lock, body: () -> Unit) { + lock.lock() + try { + body() + } + finally { + lock.unlock() + } + } +} + +data class InventoryPair(val item: InventoryItem, val amount: Int) \ No newline at end of file diff --git a/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt b/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt index 2ab424b20..a9193d9d4 100644 --- a/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt +++ b/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt @@ -53,6 +53,7 @@ open class HumanoidNPC( actorValue[AVKey.SCALE] = value } override var category = "npc" + override val originalName: String = actorValue.getAsString(AVKey.NAME) ?: "NPC" override fun secondaryUse(gc: GameContainer, delta: Int) { // TODO place this Actor to the world diff --git a/src/net/torvald/terrarum/gameitem/InventoryItem.kt b/src/net/torvald/terrarum/gameitem/InventoryItem.kt index 0316cffd1..cdd1739c0 100644 --- a/src/net/torvald/terrarum/gameitem/InventoryItem.kt +++ b/src/net/torvald/terrarum/gameitem/InventoryItem.kt @@ -1,12 +1,14 @@ package net.torvald.terrarum.gameitem import net.torvald.terrarum.itemproperties.Material +import net.torvald.terrarum.langpack.Lang +import org.newdawn.slick.Color import org.newdawn.slick.GameContainer /** * Created by minjaesong on 16-01-16. */ -abstract class InventoryItem { +abstract class InventoryItem : Comparable { /** * Internal ID of an Item, Long * 0-4095: Tiles @@ -16,6 +18,21 @@ abstract class InventoryItem { */ abstract val id: Int + abstract protected val originalName: String + + private var newName: String = "SET THE NAME!!" + + var name: String + set(value) { + newName = value + isCustomName = true + } + get() = if (isCustomName) newName else Lang[originalName] + open var isCustomName = false // true: reads from lang + + var nameColour = Color.white + + abstract var baseMass: Double abstract var baseToolSize: Double? @@ -59,6 +76,12 @@ abstract class InventoryItem { */ open var scale: Double = 1.0 + /** + * Set to zero if durability not applicable + */ + open var maxDurability: Double = 0.0 + open var durability: Double = maxDurability + /** * Effects applied continuously while in pocket */ @@ -107,6 +130,16 @@ abstract class InventoryItem { if (other == null) return false return id == (other as InventoryItem).id } + + fun unsetCustomName() { + name = originalName + isCustomName = false + nameColour = Color.white + } + + override fun compareTo(other: InventoryItem): Int = (this.id - other.id).sign() + + fun Int.sign(): Int = if (this > 0) 1 else if (this < 0) -1 else 0 } object EquipPosition { diff --git a/src/net/torvald/terrarum/itemproperties/ItemCodex.kt b/src/net/torvald/terrarum/itemproperties/ItemCodex.kt index 1c3e9dbda..0ece472a9 100644 --- a/src/net/torvald/terrarum/itemproperties/ItemCodex.kt +++ b/src/net/torvald/terrarum/itemproperties/ItemCodex.kt @@ -42,6 +42,7 @@ object ItemCodex { override var baseToolSize: Double? = null override var equipPosition = EquipPosition.HAND_GRIP override var category = "block" + override val originalName = TileCodex[i].nameKey override fun primaryUse(gc: GameContainer, delta: Int) { // TODO base punch attack diff --git a/src/net/torvald/terrarum/ui/UIItemTextButton.kt b/src/net/torvald/terrarum/ui/UIItemTextButton.kt index 04b3999eb..4df3c201c 100644 --- a/src/net/torvald/terrarum/ui/UIItemTextButton.kt +++ b/src/net/torvald/terrarum/ui/UIItemTextButton.kt @@ -24,12 +24,13 @@ class UIItemTextButton( val highlightCol: Color = Color(0x00f8ff), val highlightBackCol: Color = Color(0xb0b0b0), val highlightBackBlendMode: String = BlendMode.MULTIPLY, - val inactiveCol: Color = Color(0xc8c8c8) + val inactiveCol: Color = UIItemTextButton.defaultInactiveCol ) : UIItem(parentUI) { companion object { val font = Terrarum.fontGame!! val height = font.lineHeight * 2 + val defaultInactiveCol: Color = Color(0xc8c8c8) } private val label: String