From f2ae2d944921348eff753fac7b0d586b67ef9f62 Mon Sep 17 00:00:00 2001 From: Song Minjae Date: Mon, 17 Apr 2017 02:18:52 +0900 Subject: [PATCH] fixes, bits and pieces, changes in ID referencing, terrain and wall takes damage, working test pickaxe, and a new issue --- REFERENCING.md | 4 +- assets/locales/en/tiles.json | 11 ++ assets/locales/koKR/tiles.json | 20 +-- src/net/torvald/serialise/WriteGameMapData.kt | 4 +- src/net/torvald/terrarum/KVHashMap.kt | 16 +- src/net/torvald/terrarum/StateUITest.kt | 8 +- .../torvald/terrarum/UIItemInventoryElem.kt | 2 +- src/net/torvald/terrarum/gameactors/Actor.kt | 4 +- .../terrarum/gameactors/ActorHumanoid.kt | 2 +- .../terrarum/gameactors/ActorInventory.kt | 4 +- .../terrarum/gameactors/DroppedItem.kt | 2 +- .../terrarum/gameactors/HistoricalFigure.kt | 2 + .../terrarum/gameactors/HumanoidNPC.kt | 20 ++- .../terrarum/gameactors/InjectCreatureRaw.kt | 2 - .../gameactors/PlayerBuilderSigrid.kt | 4 +- .../torvald/terrarum/gameactors/Pocketed.kt | 10 +- .../terrarum/gameactors/ai/AILuaAPI.kt | 2 +- .../torvald/terrarum/gameitem/DynamicItem.kt | 7 - src/net/torvald/terrarum/gameitem/IVKey.kt | 3 + .../terrarum/gameitem/InventoryItem.kt | 33 ++-- .../torvald/terrarum/gameworld/GameWorld.kt | 81 ++++++---- .../terrarum/gameworld/WorldSimulator.kt | 4 +- .../torvald/terrarum/gameworld/WorldTime.kt | 2 - .../terrarum/gameworld/WorldTime_old.kt | 2 +- .../terrarum/itemproperties/ItemCodex.kt | 108 ++++++++++--- .../itemproperties/ItemEffectsLuaAPI.kt | 61 ++++++++ src/net/torvald/terrarum/langpack/Lang.kt | 2 +- .../torvald/terrarum/mapdrawer/TilesDrawer.kt | 24 +-- .../terrarum/realestate/RealEstateUtility.kt | 7 +- .../torvald/terrarum/tileproperties/Tile.kt | 2 +- .../terrarum/tileproperties/TileCodex.kt | 23 ++- .../terrarum/tileproperties/TilePropCSV.kt | 2 +- src/net/torvald/terrarum/ui/UICanvas.kt | 76 ++++++++- src/net/torvald/terrarum/ui/UIInventory.kt | 19 +-- .../virtualcomputer/luaapi/FilesystemTEVD.kt | 8 +- .../terrarum/virtualcomputer/tvd/VDUtil.kt | 147 +++++++----------- .../virtualcomputer/tvd/VirtualDisk.kt | 23 ++- work_files/Attack momentum calculator.xlsx | Bin 0 -> 30623 bytes work_files/Pickaxe Power.xlsx | Bin 0 -> 37591 bytes work_files/phys penetration compensation.pdf | Bin 0 -> 47787 bytes 40 files changed, 502 insertions(+), 249 deletions(-) create mode 100644 src/net/torvald/terrarum/itemproperties/ItemEffectsLuaAPI.kt create mode 100644 work_files/Attack momentum calculator.xlsx create mode 100644 work_files/Pickaxe Power.xlsx create mode 100644 work_files/phys penetration compensation.pdf diff --git a/REFERENCING.md b/REFERENCING.md index f1b29dfcc..8a4369819 100644 --- a/REFERENCING.md +++ b/REFERENCING.md @@ -1,7 +1,9 @@ |Range|Description| |-----|-----------| |0..4095|Tiles| -|4096..32767|Items (static)| +|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| diff --git a/assets/locales/en/tiles.json b/assets/locales/en/tiles.json index ddfc515a3..e603fd9a1 100644 --- a/assets/locales/en/tiles.json +++ b/assets/locales/en/tiles.json @@ -26,10 +26,15 @@ "TILE_SAND": "Sand", "TILE_SAND_PLURAL": "Sands", "TILE_SAND_WHITE": "White sand", + "TILE_SAND_WHITE_PLURAL": "White sands", "TILE_SAND_RED": "Red sand", + "TILE_SAND_RED_PLURAL": "Red sands", "TILE_SAND_DESERT": "Sand", + "TILE_SAND_DESERT_PLURAL": "Sands", "TILE_SAND_BLACK": "Black sand", + "TILE_SAND_BLACK_PLURAL": "Black sands", "TILE_SAND_GREEN": "Green sand", + "TILE_SAND_GREEN_PLURAL": "Green sands", "TILE_GRAVEL": "Gravel", "TILE_GRAVEL_PLURAL": "Gravels", "TILE_ORE_MALACHITE": "Malachite", @@ -77,11 +82,17 @@ "TILE_TORCH": "Torch", "TILE_TORCH_PLURAL": "Torches", "TILE_SANDSTONE": "Sandstone", + "TILE_SANDSTONE_PLURAL": "Sandstones", "TILE_SANDSTONE_WHITE": "White sandstone", + "TILE_SANDSTONE_WHITE_PLURAL": "White sandstones", "TILE_SANDSTONE_RED": "Red sandstone", + "TILE_SANDSTONE_RED_PLURAL": "Red sandstones", "TILE_SANDSTONE_DESERT": "Sandstone", + "TILE_SANDSTONE_DESERT_PLURAL": "Sandstones", "TILE_SANDSTONE_BLACK": "Black sandstone", + "TILE_SANDSTONE_BLACK_PLURAL": "Black sandstones", "TILE_SANDSTONE_GREEN": "Green sandstone", + "TILE_SANDSTONE_GREEN_PLURAL": "Green sandstones", "TILE_WATER": "Water", "TILE_WATER_PLURAL": "Waters", "TILE_LAVA": "Lava", diff --git a/assets/locales/koKR/tiles.json b/assets/locales/koKR/tiles.json index 45fcfbea9..9cd5c0dfb 100644 --- a/assets/locales/koKR/tiles.json +++ b/assets/locales/koKR/tiles.json @@ -7,22 +7,22 @@ "TILE_GRAS_PLURALS": "잔디", "TILE_PLANK_NORMAL": "나무판자", "TILE_PLANK_NORMAL_PLURAL": "나무판자", - "TILE_PLANK_EBONY": "흑단", - "TILE_PLANK_EBONY_PLURAL": "흑단", - "TILE_PLANK_BIRCH": "백단", - "TILE_PLANK_BIRCH_PLURAL": "백단", - "TILE_PLANK_BLOODROSE": "자단", - "TILE_PLANK_BLOODROSE_PLURAL": "자단", + "TILE_PLANK_EBONY": "검정 나무판자", + "TILE_PLANK_EBONY_PLURAL": "검정 나무판자", + "TILE_PLANK_BIRCH": "하양 나무판자", + "TILE_PLANK_BIRCH_PLURAL": "하양 나무판자", + "TILE_PLANK_BLOODROSE": "빨강 나무판자", + "TILE_PLANK_BLOODROSE_PLURAL": "빨강 나무판자", "TILE_TRUNK_NORMAL": "통나무", "TILE_TRUNK_NORMAL_PLURAL": "통나무", "TILE_TRUNK_EBONY": "흑단나무", "TILE_TRUNK_EBONY_PLURAL": "흑단나무", - "TILE_TRUNK_BIRCH": "백단나무", - "TILE_TRUNK_BIRCH_PLURAL": "백단나무", + "TILE_TRUNK_BIRCH": "자작나무", + "TILE_TRUNK_BIRCH_PLURAL": "자작나무", "TILE_TRUNK_BLOODROSE": "자단나무", "TILE_TRUNK_BLOODROSE_PLURAL": "자단나무", - "TILE_STONE_QUARRIED": "캔 돌", - "TILE_STONE_QUARRIED_PLURAL": "캔 돌", + "TILE_STONE_QUARRIED": "석재", + "TILE_STONE_QUARRIED_PLURAL": "석재", "TILE_SAND": "모래", "TILE_SAND_PLURAL": "모래", "TILE_GRAVEL": "자갈", diff --git a/src/net/torvald/serialise/WriteGameMapData.kt b/src/net/torvald/serialise/WriteGameMapData.kt index aef54ef5b..8d8d32194 100644 --- a/src/net/torvald/serialise/WriteGameMapData.kt +++ b/src/net/torvald/serialise/WriteGameMapData.kt @@ -43,9 +43,9 @@ object WriteGameMapData { { b -> Files.write(tempPath, byteArrayOf(b)) }) map.layerWall.forEach( { b -> Files.write(tempPath, byteArrayOf(b)) }) - map.terrainDamage.forEach( + map.layerTerrainLowBits.forEach( { b -> Files.write(tempPath, byteArrayOf(b)) }) - map.wallDamage.forEach( + map.layerWallLowBits.forEach( { b -> Files.write(tempPath, byteArrayOf(b)) }) map.layerWire.forEach( { b -> Files.write(tempPath, byteArrayOf(b)) }) diff --git a/src/net/torvald/terrarum/KVHashMap.kt b/src/net/torvald/terrarum/KVHashMap.kt index 99d5069a5..6a8dc6c1f 100644 --- a/src/net/torvald/terrarum/KVHashMap.kt +++ b/src/net/torvald/terrarum/KVHashMap.kt @@ -3,6 +3,7 @@ package net.torvald.terrarum import com.google.gson.JsonPrimitive import java.util.* import java.util.function.Consumer +import kotlin.collections.HashMap typealias ActorValue = KVHashMap typealias ItemValue = KVHashMap @@ -13,7 +14,15 @@ typealias GameConfig = KVHashMap */ class KVHashMap { - private val hashMap = HashMap() + constructor() { + hashMap = HashMap() + } + + private constructor(newMap: HashMap) { + hashMap = newMap + } + + private val hashMap: HashMap /** * Add key-value pair to the configuration table. @@ -108,4 +117,9 @@ class KVHashMap { hashMap.remove(key, hashMap[key]!!) } + fun clone(): KVHashMap { + val cloneOfMap = hashMap.clone() as HashMap + return KVHashMap(cloneOfMap) + } + } \ No newline at end of file diff --git a/src/net/torvald/terrarum/StateUITest.kt b/src/net/torvald/terrarum/StateUITest.kt index a933e9517..c1566d4dc 100644 --- a/src/net/torvald/terrarum/StateUITest.kt +++ b/src/net/torvald/terrarum/StateUITest.kt @@ -52,9 +52,9 @@ class StateUITest : BasicGameState() { override var originalName: String = "Test tool" override var baseMass: Double = 12.0 override var baseToolSize: Double? = 8.0 - override var category: String = InventoryItem.Category.TOOL - override var maxDurability: Double = 10.0 - override var durability: Double = 6.43 + override var inventoryCategory: String = InventoryItem.Category.TOOL + override var maxDurability: Int = 143 + override var durability: Float = 64f override var consumable = false }) actor.inventory.getByID(5656)!!.item.name = "Test tool" @@ -68,7 +68,7 @@ class StateUITest : BasicGameState() { override var originalName: String = "CONTEXT_ITEM_QUEST_NOUN" override var baseMass: Double = 1.4 override var baseToolSize: Double? = null - override var category: String = InventoryItem.Category.MISC + override var inventoryCategory: String = InventoryItem.Category.MISC override var consumable = false }) diff --git a/src/net/torvald/terrarum/UIItemInventoryElem.kt b/src/net/torvald/terrarum/UIItemInventoryElem.kt index 7b29d992e..8a14773bd 100644 --- a/src/net/torvald/terrarum/UIItemInventoryElem.kt +++ b/src/net/torvald/terrarum/UIItemInventoryElem.kt @@ -106,7 +106,7 @@ class UIItemInventoryElem( g.lineWidth = 3f g.drawLine(barOffset, posY + durabilityBarOffY, barOffset + barFullLen, posY + durabilityBarOffY) g.color = durabilityCol - g.drawLine(barOffset, posY + durabilityBarOffY, barOffset + barFullLen * (item!!.durability / item!!.maxDurability).toFloat(), posY + durabilityBarOffY) + g.drawLine(barOffset, posY + durabilityBarOffY, barOffset + barFullLen * (item!!.durability / item!!.maxDurability), posY + durabilityBarOffY) } diff --git a/src/net/torvald/terrarum/gameactors/Actor.kt b/src/net/torvald/terrarum/gameactors/Actor.kt index 121baa0f4..6f8876acf 100644 --- a/src/net/torvald/terrarum/gameactors/Actor.kt +++ b/src/net/torvald/terrarum/gameactors/Actor.kt @@ -50,9 +50,9 @@ abstract class Actor(val renderOrder: RenderOrder) : Comparable, Runnable fun hasCollision(value: Int) = try { Terrarum.ingame!!.theGameHasActor(value) || - value < ItemCodex.ITEM_COUNT_MAX || + value < ItemCodex.ACTOR_ID_MIN || value < when (renderOrder) { - RenderOrder.BEHIND -> ItemCodex.ITEM_COUNT_MAX + RenderOrder.BEHIND -> ItemCodex.ACTOR_ID_MIN RenderOrder.MIDDLE -> 0x10000000 RenderOrder.MIDTOP -> 0x60000000 RenderOrder.FRONT -> 0x70000000 diff --git a/src/net/torvald/terrarum/gameactors/ActorHumanoid.kt b/src/net/torvald/terrarum/gameactors/ActorHumanoid.kt index 3584cdbfe..d065fcd22 100644 --- a/src/net/torvald/terrarum/gameactors/ActorHumanoid.kt +++ b/src/net/torvald/terrarum/gameactors/ActorHumanoid.kt @@ -138,7 +138,7 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null) override val isUnique: Boolean = false override var baseMass: Double = 0.0 override var baseToolSize: Double? = null - override var category = "should_not_be_seen" + override var inventoryCategory = "should_not_be_seen" override val originalName: String = actorValue.getAsString(AVKey.NAME) ?: "(no name)" override var consumable = false } diff --git a/src/net/torvald/terrarum/gameactors/ActorInventory.kt b/src/net/torvald/terrarum/gameactors/ActorInventory.kt index df70a005c..468a88203 100644 --- a/src/net/torvald/terrarum/gameactors/ActorInventory.kt +++ b/src/net/torvald/terrarum/gameactors/ActorInventory.kt @@ -126,7 +126,9 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode remove(item, 1) } else { - // TODO decrement durability + item.durability -= 1f + if (item.durability <= 0) + remove(item, 1) } } diff --git a/src/net/torvald/terrarum/gameactors/DroppedItem.kt b/src/net/torvald/terrarum/gameactors/DroppedItem.kt index a4f00d899..0c1a045fc 100644 --- a/src/net/torvald/terrarum/gameactors/DroppedItem.kt +++ b/src/net/torvald/terrarum/gameactors/DroppedItem.kt @@ -12,7 +12,7 @@ import org.newdawn.slick.Graphics class DroppedItem(private val item: InventoryItem) : ActorWithSprite(Actor.RenderOrder.MIDTOP) { init { - if (item.id >= ItemCodex.ITEM_COUNT_MAX) + if (item.id >= ItemCodex.ACTOR_ID_MIN) throw RuntimeException("Attempted to create DroppedItem actor of a real actor; the real actor must be dropped instead.") isVisible = true diff --git a/src/net/torvald/terrarum/gameactors/HistoricalFigure.kt b/src/net/torvald/terrarum/gameactors/HistoricalFigure.kt index c6b6f037a..9f78b3dce 100644 --- a/src/net/torvald/terrarum/gameactors/HistoricalFigure.kt +++ b/src/net/torvald/terrarum/gameactors/HistoricalFigure.kt @@ -3,6 +3,8 @@ package net.torvald.terrarum.gameactors import net.torvald.terrarum.gameworld.WorldTime import org.newdawn.slick.Input +typealias AnyPlayer = HistoricalFigure + /** * An actor (NPC) which has life and death, * though death might not exist if it has achieved immortality :) diff --git a/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt b/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt index 84c0bcdb4..371c4c266 100644 --- a/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt +++ b/src/net/torvald/terrarum/gameactors/HumanoidNPC.kt @@ -1,9 +1,12 @@ package net.torvald.terrarum.gameactors +import net.torvald.terrarum.Terrarum import net.torvald.terrarum.gameactors.ActorHumanoid import net.torvald.terrarum.gameactors.ai.AILuaAPI import net.torvald.terrarum.gameactors.ai.ActorAI import net.torvald.terrarum.gameactors.ai.LuaAIWrapper +import net.torvald.terrarum.gamecontroller.mouseX +import net.torvald.terrarum.gamecontroller.mouseY import net.torvald.terrarum.gameitem.InventoryItem import org.luaj.vm2.* import org.luaj.vm2.compiler.LuaC @@ -51,13 +54,22 @@ open class HumanoidNPC( set(value) { actorValue[AVKey.SCALE] = value } - override var category = "npc" + override var inventoryCategory = "npc" override val originalName: String = actorValue.getAsString(AVKey.NAME) ?: "NPC" - override var consumable = false + override var consumable = true override fun secondaryUse(gc: GameContainer, delta: Int): Boolean { - return false - // TODO place this Actor to the world + try { + // place the actor to the world + this@HumanoidNPC.setPosition(gc.mouseX, gc.mouseY) + Terrarum.ingame!!.addNewActor(this@HumanoidNPC) + // successful + return true + } + catch (e: Exception) { + e.printStackTrace() + return false + } } } diff --git a/src/net/torvald/terrarum/gameactors/InjectCreatureRaw.kt b/src/net/torvald/terrarum/gameactors/InjectCreatureRaw.kt index 00c75dd21..1862ac106 100644 --- a/src/net/torvald/terrarum/gameactors/InjectCreatureRaw.kt +++ b/src/net/torvald/terrarum/gameactors/InjectCreatureRaw.kt @@ -15,8 +15,6 @@ import java.security.SecureRandom */ object InjectCreatureRaw { - // FIXME strength not injected properly? - const val JSONPATH = "./assets/raw/creatures/" private const val JSONMULT = "mult" // one appears in JSON files diff --git a/src/net/torvald/terrarum/gameactors/PlayerBuilderSigrid.kt b/src/net/torvald/terrarum/gameactors/PlayerBuilderSigrid.kt index e2c34f99f..446529b55 100644 --- a/src/net/torvald/terrarum/gameactors/PlayerBuilderSigrid.kt +++ b/src/net/torvald/terrarum/gameactors/PlayerBuilderSigrid.kt @@ -58,6 +58,7 @@ object PlayerBuilderSigrid { p.actorValue[AVKey.INTELLIGENT] = true p.actorValue[AVKey.LUMINOSITY] = Color(0x434aff).to10bit() + //p.actorValue[AVKey.LUMINOSITY] = 214127943 // bright purple p.actorValue[AVKey.BASEDEFENCE] = 141 @@ -65,7 +66,7 @@ object PlayerBuilderSigrid { //p.actorValue["__selectedtile"] = 147 // test code; replace with .primaryUse(gc, delta) p.actorValue["__aimhelper"] = true // TODO when you'll gonna implement it? - p.setHitboxDimension(15, p.actorValue.getAsInt(AVKey.BASEHEIGHT)!!, 11, 0) // FIXME offsetY of -2: Have no idea about the error; it's just supposed to be zero + p.setHitboxDimension(15, p.actorValue.getAsInt(AVKey.BASEHEIGHT)!!, 11, 0) p.inventory = ActorInventory(p, 0, ActorInventory.CAPACITY_MODE_NO_ENCUMBER) @@ -85,6 +86,7 @@ object PlayerBuilderSigrid { Tile.STONE_QUARRIED, Tile.STONE_TILE_WHITE, Tile.TORCH ) tiles.forEach { p.inventory.add(it, 999) } + p.inventory.add(ItemCodex.ITEM_STATIC.first) diff --git a/src/net/torvald/terrarum/gameactors/Pocketed.kt b/src/net/torvald/terrarum/gameactors/Pocketed.kt index 0d59517da..bdd7cdc77 100644 --- a/src/net/torvald/terrarum/gameactors/Pocketed.kt +++ b/src/net/torvald/terrarum/gameactors/Pocketed.kt @@ -3,7 +3,6 @@ package net.torvald.terrarum.gameactors import net.torvald.terrarum.Terrarum import net.torvald.terrarum.gameitem.InventoryItem import net.torvald.terrarum.itemproperties.ItemCodex -import java.util.* /** * Created by minjaesong on 16-01-15. @@ -17,10 +16,13 @@ interface Pocketed { */ fun unequipItem(item: InventoryItem) { if (item.equipPosition == InventoryItem.EquipPosition.NULL) - throw Error("Unequipping the item that cannot be equipped") + throw Error("Unequipping the item that cannot be equipped in the first place") - if (!inventory.contains(item)) - throw Error("Unequipping the item that does not exist in inventory") + if (!inventory.contains(item)) { + //throw Error("Unequipping the item that does not exist in inventory") + System.err.println("[Pocketed] Warning -- Unequipping the item that does not exist in inventory") + return // just do nothing + } inventory.itemEquipped[item.equipPosition] = null item.effectOnUnequip(Terrarum.appgc, Terrarum.UPDATE_DELTA) diff --git a/src/net/torvald/terrarum/gameactors/ai/AILuaAPI.kt b/src/net/torvald/terrarum/gameactors/ai/AILuaAPI.kt index 2b640845d..336c784cb 100644 --- a/src/net/torvald/terrarum/gameactors/ai/AILuaAPI.kt +++ b/src/net/torvald/terrarum/gameactors/ai/AILuaAPI.kt @@ -239,7 +239,7 @@ internal class AILuaAPI(g: Globals, actor: ActorWithSprite) { luatable[y - feetTilePos[1]] = LuaTable() for (x in feetTilePos[0] - radius..feetTilePos[0] + radius) { - val tile = TileCodex[Terrarum.ingame!!.world.getTileFromTerrain(x, y) ?: 4096] + val tile = TileCodex[Terrarum.ingame!!.world.getTileFromTerrain(x, y) ?: Tile.NULL] val solidity = tile.isSolid.toInt() val liquidity = tile.isFluid.toInt() val gravity = tile.isFallable.toInt() diff --git a/src/net/torvald/terrarum/gameitem/DynamicItem.kt b/src/net/torvald/terrarum/gameitem/DynamicItem.kt index d18427d5f..a5583d60e 100644 --- a/src/net/torvald/terrarum/gameitem/DynamicItem.kt +++ b/src/net/torvald/terrarum/gameitem/DynamicItem.kt @@ -16,13 +16,6 @@ import org.newdawn.slick.GameContainer open abstract class DynamicItem(val baseItemID: Int?, newMass: Double? = null, newScale: Double? = null) : InventoryItem() { /* - /** - * Internal ID of an Item, Long - * 0-4096: Tiles - * 4097-32767: Static items - * 32768-16777215: Dynamic items - * >= 16777216: Actor RefID - */ override val id: Int = generateUniqueDynamicItemID() private fun generateUniqueDynamicItemID(): Int { diff --git a/src/net/torvald/terrarum/gameitem/IVKey.kt b/src/net/torvald/terrarum/gameitem/IVKey.kt index 47802b791..98129d76e 100644 --- a/src/net/torvald/terrarum/gameitem/IVKey.kt +++ b/src/net/torvald/terrarum/gameitem/IVKey.kt @@ -7,6 +7,9 @@ object IVKey { const val ITEMTYPE = "itemtype" // "sword1h", "sword2h", "pick", "hammer", "tile", "wall", etc const val UUID = "uuid" // some items need UUID to be stored + const val BASE_WEAPON_POWER = "baseweaponpower" + const val BASE_PICK_POWER = "basepickpower" + object ItemType { const val BLOCK = "tile" diff --git a/src/net/torvald/terrarum/gameitem/InventoryItem.kt b/src/net/torvald/terrarum/gameitem/InventoryItem.kt index a37b5acae..031a9f4c7 100644 --- a/src/net/torvald/terrarum/gameitem/InventoryItem.kt +++ b/src/net/torvald/terrarum/gameitem/InventoryItem.kt @@ -10,17 +10,12 @@ import org.newdawn.slick.GameContainer /** * Created by minjaesong on 16-01-16. */ -abstract class InventoryItem : Comparable { - /** - * Internal ID of an Item, - * 0-4095: Tiles - * 4096-32767: Unique items (isUnique = true), brand-new tools - * 32768-16777215: Dynamic items (e.g. tools with damage) - * >= 16777216: Actor RefID - */ +abstract class InventoryItem : Comparable, Cloneable { + abstract val id: Int /** + * * e.g. Key Items (in a Pokémon sense), floppies */ abstract val isUnique: Boolean @@ -47,11 +42,11 @@ abstract class InventoryItem : Comparable { abstract var baseToolSize: Double? - abstract var category: String // "weapon", "tool", "armor", etc. (all smallcaps) + abstract var inventoryCategory: String // "weapon", "tool", "armor", etc. (all smallcaps) var itemProperties = ItemValue() - /** Single-use then destroyed (e.g. Tiles) */ + /** Single-use then destroyed (e.g. Tiles), aka negation of "stackable" */ abstract var consumable: Boolean /** @@ -94,9 +89,12 @@ abstract class InventoryItem : Comparable { /** * Set to zero if durability not applicable */ - open var maxDurability: Double = 0.0 + open var maxDurability: Int = 0 - open var durability: Double = 0.0 + /** + * Float. NOT A MISTAKE + */ + open var durability: Float = 0f /** * Effects applied continuously while in pocket @@ -115,6 +113,9 @@ abstract class InventoryItem : Comparable { * @return true when used successfully, false otherwise * * note: DO NOT super(gc, g) this! + * + * Consumption function is executed in net.torvald.terrarum.gamecontroller.GameController, + * in which the function itself is defined in net.torvald.terrarum.gameactors.ActorInventory */ open fun primaryUse(gc: GameContainer, delta: Int): Boolean = false @@ -212,4 +213,12 @@ abstract class InventoryItem : Comparable { const val WALL = "wall" const val MISC = "misc" } + + override public fun clone(): InventoryItem { + val clonedItem = super.clone() + // properly clone ItemValue + (clonedItem as InventoryItem).itemProperties = this.itemProperties.clone() + + return clonedItem + } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/gameworld/GameWorld.kt b/src/net/torvald/terrarum/gameworld/GameWorld.kt index 17fe7fa34..dcc09c852 100644 --- a/src/net/torvald/terrarum/gameworld/GameWorld.kt +++ b/src/net/torvald/terrarum/gameworld/GameWorld.kt @@ -1,35 +1,30 @@ package net.torvald.terrarum.gameworld +import net.torvald.terrarum.realestate.RealEstateUtility import org.dyn4j.geometry.Vector2 import org.newdawn.slick.SlickException -class GameWorld -/** - * @param width - * * - * @param height - * * - * @throws SlickException - */ -@Throws(SlickException::class) -constructor(//properties - val width: Int, val height: Int) { +typealias TileAddress = Long +typealias TileDamage = Int + +class GameWorld(val width: Int, val height: Int) { + //layers val layerWall: MapLayer - /** - * Get MapLayer object of terrain - - * @return MapLayer terrain layer - */ val layerTerrain: MapLayer val layerWire: MapLayer - val wallDamage: PairedMapLayer - val terrainDamage: PairedMapLayer + + val layerWallLowBits: PairedMapLayer + val layerTerrainLowBits: PairedMapLayer + val spawnX: Int val spawnY: Int + val wallDamages = HashMap() + val terrainDamages = HashMap() + //public World physWorld = new World( new Vec2(0, -TerrarumMain.game.gravitationalAccel) ); //physics /** Meter per second squared. Currently only the downward gravity is supported. No reverse gravity :p */ @@ -47,8 +42,8 @@ constructor(//properties layerTerrain = MapLayer(width, height) layerWall = MapLayer(width, height) layerWire = MapLayer(width, height) - terrainDamage = PairedMapLayer(width, height) - wallDamage = PairedMapLayer(width, height) + layerTerrainLowBits = PairedMapLayer(width, height) + layerWallLowBits = PairedMapLayer(width, height) time = WorldTime( 71 * WorldTime.DAY_LENGTH + @@ -87,11 +82,11 @@ constructor(//properties * @return byte[][] damage code pair */ val damageDataArray: Array - get() = terrainDamage.dataPair + get() = layerTerrainLowBits.dataPair fun getTileFromWall(x: Int, y: Int): Int? { val wall: Int? = layerWall.getTile(x fmod width, y) - val wallDamage: Int? = getWallDamage(x fmod width, y) + val wallDamage: Int? = getWallLowBits(x fmod width, y) return if (wall == null || wallDamage == null) null else @@ -100,7 +95,7 @@ constructor(//properties fun getTileFromTerrain(x: Int, y: Int): Int? { val terrain: Int? = layerTerrain.getTile(x fmod width, y) - val terrainDamage: Int? = getTerrainDamage(x fmod width, y) + val terrainDamage: Int? = getTerrainLowBits(x fmod width, y) return if (terrain == null || terrainDamage == null) null else @@ -111,12 +106,12 @@ constructor(//properties return layerWire.getTile(x fmod width, y) } - fun getWallDamage(x: Int, y: Int): Int? { - return wallDamage.getData(x fmod width, y) + fun getWallLowBits(x: Int, y: Int): Int? { + return layerWallLowBits.getData(x fmod width, y) } - fun getTerrainDamage(x: Int, y: Int): Int? { - return terrainDamage.getData(x fmod width, y) + fun getTerrainLowBits(x: Int, y: Int): Int? { + return layerTerrainLowBits.getData(x fmod width, y) } /** @@ -145,12 +140,12 @@ constructor(//properties fun setTileWall(x: Int, y: Int, tile: Byte, damage: Int) { layerWall.setTile(x fmod width, y, tile) - wallDamage.setData(x fmod width, y, damage) + layerWallLowBits.setData(x fmod width, y, damage) } fun setTileTerrain(x: Int, y: Int, tile: Byte, damage: Int) { layerTerrain.setTile(x fmod width, y, tile) - terrainDamage.setData(x fmod width, y, damage) + layerTerrainLowBits.setData(x fmod width, y, damage) } fun setTileWire(x: Int, y: Int, tile: Byte) { @@ -216,6 +211,32 @@ constructor(//properties } } + fun inflctTerrainDamage(x: Int, y: Int, damage: Int) { + val addr = RealEstateUtility.getAbsoluteTileNumber(x, y) + + if (terrainDamages[addr] == null) { + terrainDamages[addr] = damage + } + else { + terrainDamages[addr] = terrainDamages[addr]!! + damage + } + } + fun getTerrainDamage(x: Int, y: Int) = + terrainDamages[RealEstateUtility.getAbsoluteTileNumber(x, y)] ?: 0 + + fun inflctWallDamage(x: Int, y: Int, damage: Int) { + val addr = RealEstateUtility.getAbsoluteTileNumber(x, y) + + if (wallDamages[addr] == null) { + wallDamages[addr] = damage + } + else { + wallDamages[addr] = wallDamages[addr]!! + damage + } + } + fun getWallDamage(x: Int, y: Int) = + wallDamages[RealEstateUtility.getAbsoluteTileNumber(x, y)] ?: 0 + companion object { @Transient val WALL = 0 @@ -224,7 +245,7 @@ constructor(//properties @Transient val TILES_SUPPORTED = MapLayer.RANGE * PairedMapLayer.RANGE @Transient val SIZEOF: Byte = MapLayer.SIZEOF - @Transient val LAYERS: Byte = 4 // terrain, wall (terrainDamage + wallDamage), wire + @Transient val LAYERS: Byte = 4 // terrain, wall (layerTerrainLowBits + layerWallLowBits), wire } } diff --git a/src/net/torvald/terrarum/gameworld/WorldSimulator.kt b/src/net/torvald/terrarum/gameworld/WorldSimulator.kt index cf2d5fa4e..2140e9648 100644 --- a/src/net/torvald/terrarum/gameworld/WorldSimulator.kt +++ b/src/net/torvald/terrarum/gameworld/WorldSimulator.kt @@ -2,6 +2,7 @@ package net.torvald.terrarum.gameworld import net.torvald.random.HQRNG import net.torvald.terrarum.Terrarum +import net.torvald.terrarum.gameactors.AnyPlayer import net.torvald.terrarum.gameactors.HistoricalFigure import net.torvald.terrarum.gameactors.Player import net.torvald.terrarum.gameactors.roundInt @@ -40,8 +41,7 @@ object WorldSimulator { private val world = Terrarum.ingame!!.world - // TODO future Kotlin feature -- typealias AnyPlayer: HistoricalFigure - operator fun invoke(p: HistoricalFigure?, delta: Int) { + operator fun invoke(p: AnyPlayer?, delta: Int) { if (p != null) { updateXFrom = p.hitbox.centeredX.div(FeaturesDrawer.TILE_SIZE).minus(FLUID_UPDATING_SQUARE_RADIUS).roundInt() updateYFrom = p.hitbox.centeredY.div(FeaturesDrawer.TILE_SIZE).minus(FLUID_UPDATING_SQUARE_RADIUS).roundInt() diff --git a/src/net/torvald/terrarum/gameworld/WorldTime.kt b/src/net/torvald/terrarum/gameworld/WorldTime.kt index 6c161dcf5..be201d0af 100644 --- a/src/net/torvald/terrarum/gameworld/WorldTime.kt +++ b/src/net/torvald/terrarum/gameworld/WorldTime.kt @@ -98,8 +98,6 @@ class WorldTime(initTime: Long = 0L) { ) val DAY_NAMES_SHORT = arrayOf("Mon", "Tys", "Mid", "Tor", "Fre", "Lau", "Sun", "Ver") - // FIXME Next to Granite is Felsite - val MONTH_NAMES = arrayOf( "Opal", "Obsidian", "Granite", "Slate", "Felsite", "Hematite", "Malachite", "Galena", "Limestone", "Sandstone", "Timber", "Moonstone" diff --git a/src/net/torvald/terrarum/gameworld/WorldTime_old.kt b/src/net/torvald/terrarum/gameworld/WorldTime_old.kt index 8a7a5623c..3cd6f287c 100644 --- a/src/net/torvald/terrarum/gameworld/WorldTime_old.kt +++ b/src/net/torvald/terrarum/gameworld/WorldTime_old.kt @@ -16,8 +16,8 @@ import net.torvald.terrarum.gameactors.GameDate * * Created by minjaesong on 16-01-24. */ +@Deprecated("Are you even reading the name?") class YeOldeWorldTime { - internal var TIME_T = 0L // TODO use it! Epoch: Year 125, 1st Granite, 0h00:00 internal var seconds: Int // 0 - 59 internal var minutes: Int // 0 - 59 diff --git a/src/net/torvald/terrarum/itemproperties/ItemCodex.kt b/src/net/torvald/terrarum/itemproperties/ItemCodex.kt index ea49d7857..5f6040360 100644 --- a/src/net/torvald/terrarum/itemproperties/ItemCodex.kt +++ b/src/net/torvald/terrarum/itemproperties/ItemCodex.kt @@ -11,6 +11,8 @@ import net.torvald.terrarum.gamecontroller.mouseTileY import net.torvald.terrarum.gameitem.IVKey import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.mapdrawer.TilesDrawer +import net.torvald.terrarum.mapdrawer.TilesDrawer.wallOverlayColour +import net.torvald.terrarum.tileproperties.Tile import net.torvald.terrarum.tileproperties.TileCodex import org.newdawn.slick.GameContainer import org.newdawn.slick.Image @@ -28,31 +30,35 @@ object ItemCodex { private val itemCodex = HashMap() private val dynamicItemDescription = HashMap() - val ITEM_TILE_MAX = GameWorld.TILES_SUPPORTED - 1 // 4095 - val ITEM_COUNT_MAX = 1048576 - val ITEM_DYNAMIC_MAX = ITEM_COUNT_MAX - 1 - val ITEM_STATIC_MAX = 32767 - val ITEM_DYNAMIC_MIN = ITEM_STATIC_MAX + 1 - val ITEM_STATIC_MIN = ITEM_TILE_MAX + 1 // 4096 + val ITEM_TILES = 0..GameWorld.TILES_SUPPORTED - 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_STATIC = ITEM_WIRES.endInclusive + 1..32767 + val ITEM_DYNAMIC = 32768..1048575 + val ACTOR_ID_MIN = ITEM_DYNAMIC.endInclusive + 1 + private val itemImagePlaceholder = Image("./assets/item_kari_24.tga") init { // tile items (blocks and walls are the same thing basically) - for (i in 0..ITEM_TILE_MAX) { + for (i in ITEM_TILES + ITEM_WALLS) { itemCodex[i] = object : InventoryItem() { override val id: Int = 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 var category = "block" - override val originalName = TileCodex[i].nameKey + override val originalName = TileCodex[i % ITEM_WALLS.first].nameKey override var consumable = true + override var inventoryCategory = Category.BLOCK init { - itemProperties[IVKey.ITEMTYPE] = IVKey.ItemType.BLOCK + itemProperties[IVKey.ITEMTYPE] = if (i in ITEM_TILES) + IVKey.ItemType.BLOCK + else + IVKey.ItemType.WALL } override fun primaryUse(gc: GameContainer, delta: Int): Boolean { @@ -74,26 +80,81 @@ object ItemCodex { // filter passed, do the job // FIXME this is only useful for Player - Terrarum.ingame!!.world.setTileTerrain( - gc.mouseTileX, - gc.mouseTileY, - i - ) + if (i in ITEM_TILES) { + Terrarum.ingame!!.world.setTileTerrain( + gc.mouseTileX, + gc.mouseTileY, + i + ) + } + else { + Terrarum.ingame!!.world.setTileWall( + gc.mouseTileX, + gc.mouseTileY, + i + ) + } return true } } } - // read prop in csv and fill itemCodex + // test copper pickaxe + itemCodex[ITEM_STATIC.first] = object : InventoryItem() { + override val id = ITEM_STATIC.first + override val isUnique = false + override val originalName = "Test Pick" + override var baseMass = 10.0 + override var baseToolSize: Double? = 10.0 + override var consumable = false + override var maxDurability = 200 // this much tiles before breaking + override var durability = maxDurability.toFloat() + override var equipPosition = EquipPosition.HAND_GRIP + override var inventoryCategory = Category.TOOL + + init { + itemProperties[IVKey.ITEMTYPE] = IVKey.ItemType.PICK + } + + override fun primaryUse(gc: GameContainer, delta: Int): Boolean { + val mousePoint = Point2d(gc.mouseTileX.toDouble(), gc.mouseTileY.toDouble()) + // linear search filter (check for intersection with tilewise mouse point and tilewise hitbox) + Terrarum.ingame!!.actorContainer.forEach { + if (it is ActorWithSprite && it.tilewiseHitbox.intersects(mousePoint)) + return false + } + + // return false if the tile is already there + if (this.id == Terrarum.ingame!!.world.getTileFromTerrain(gc.mouseTileX, gc.mouseTileY)) + return false + + // filter passed, do the job + Terrarum.ingame!!.world.setTileTerrain( + gc.mouseTileX, + gc.mouseTileY, + Tile.AIR + ) + /*Terrarum.ingame!!.world.inflctTerrainDamage( + gc.mouseTileX, + gc.mouseTileY, + + )*/ + + + return true + } + } + + // TODO read prop in Lua and fill itemCodex // read from save (if applicable) and fill dynamicItemDescription } operator fun get(code: Int): InventoryItem { - if (code < ITEM_STATIC_MAX) // generic item - return itemCodex[code]!! // from CSV - else if (code < ITEM_DYNAMIC_MAX) { + if (code <= ITEM_STATIC.endInclusive) // generic item + return itemCodex[code]!!.clone() // from CSV + else if (code <= ITEM_DYNAMIC.endInclusive) { TODO("read from dynamicitem description (JSON)") } else { @@ -105,8 +166,15 @@ object ItemCodex { } fun getItemImage(code: Int): Image { - if (code <= ITEM_TILE_MAX) + if (code <= ITEM_TILES.endInclusive) return TilesDrawer.tilesTerrain.getSubImage((code % 16) * 16, code / 16) + else if (code <= ITEM_WALLS.endInclusive) { + val img = TilesDrawer.tilesTerrain.getSubImage((code % 16) * 16, code / 16) + img.setImageColor(wallOverlayColour.r, wallOverlayColour.g, wallOverlayColour.b) + return img + } + else if (code <= ITEM_WIRES.endInclusive) + return TilesDrawer.tilesWire.getSubImage((code % 16) * 16, code / 16) else return itemImagePlaceholder } diff --git a/src/net/torvald/terrarum/itemproperties/ItemEffectsLuaAPI.kt b/src/net/torvald/terrarum/itemproperties/ItemEffectsLuaAPI.kt new file mode 100644 index 000000000..33572eafc --- /dev/null +++ b/src/net/torvald/terrarum/itemproperties/ItemEffectsLuaAPI.kt @@ -0,0 +1,61 @@ +package net.torvald.terrarum.itemproperties + +import net.torvald.terrarum.Terrarum +import net.torvald.terrarum.gameactors.ai.toLua +import net.torvald.terrarum.gamecontroller.mouseTileX +import net.torvald.terrarum.gamecontroller.mouseTileY +import net.torvald.terrarum.gamecontroller.mouseX +import net.torvald.terrarum.gamecontroller.mouseY +import org.luaj.vm2.Globals +import org.luaj.vm2.LuaTable +import org.luaj.vm2.LuaValue +import org.luaj.vm2.lib.ThreeArgFunction +import org.luaj.vm2.lib.ZeroArgFunction + +/** + * Created by SKYHi14 on 2017-04-16. + */ +class ItemEffectsLuaAPI(g: Globals) { + + init { + g["getMouseTile"] = GetMouseTile() + g["getMousePos"] = GetMousePos() + + + + g["world"] = LuaTable() + + g["world"]["strikeEarth"] = StrikeEarth() + g["world"]["strikeWall"] = StrikeWall() + + + + g["actor"] = LuaTable() + } + + + class GetMouseTile : ZeroArgFunction() { + override fun call(): LuaValue { + return LuaValue.tableOf(arrayOf(Terrarum.appgc.mouseTileX.toLua(), Terrarum.appgc.mouseTileY.toLua())) + } + } + class GetMousePos : ZeroArgFunction() { + override fun call(): LuaValue { + return LuaValue.tableOf(arrayOf(Terrarum.appgc.mouseX.toLua(), Terrarum.appgc.mouseY.toLua())) + } + } + + class StrikeEarth : ThreeArgFunction() { + override fun call(x: LuaValue, y: LuaValue, power: LuaValue): LuaValue { + Terrarum.ingame!!.world.inflctTerrainDamage(x.checkint(), y.checkint(), power.checkint()) + return LuaValue.NONE + } + } + class StrikeWall : ThreeArgFunction() { + override fun call(x: LuaValue, y: LuaValue, power: LuaValue): LuaValue { + Terrarum.ingame!!.world.inflctWallDamage(x.checkint(), y.checkint(), power.checkint()) + return LuaValue.NONE + } + } + +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/langpack/Lang.kt b/src/net/torvald/terrarum/langpack/Lang.kt index 495f42083..84dbe13b3 100644 --- a/src/net/torvald/terrarum/langpack/Lang.kt +++ b/src/net/torvald/terrarum/langpack/Lang.kt @@ -106,7 +106,7 @@ object Lang { } operator fun get(key: String): String { - fun fallback(): String = langpack["${key}_$FALLBACK_LANG_CODE"] ?: "ERRNULL:$key" + fun fallback(): String = langpack["${key}_$FALLBACK_LANG_CODE"] ?: "$$key" val ret = langpack["${key}_${Terrarum.gameLocale}"] diff --git a/src/net/torvald/terrarum/mapdrawer/TilesDrawer.kt b/src/net/torvald/terrarum/mapdrawer/TilesDrawer.kt index d7429fc4d..f07c781e7 100644 --- a/src/net/torvald/terrarum/mapdrawer/TilesDrawer.kt +++ b/src/net/torvald/terrarum/mapdrawer/TilesDrawer.kt @@ -401,10 +401,10 @@ object TilesDrawer { */ fun getNearbyTilesInfo(x: Int, y: Int, mode: Int, mark: Int?): Int { val nearbyTiles = IntArray(4) - nearbyTiles[NEARBY_TILE_KEY_LEFT] = world.getTileFrom(mode, x - 1, y) ?: 4096 - nearbyTiles[NEARBY_TILE_KEY_RIGHT] = world.getTileFrom(mode, x + 1, y) ?: 4096 + nearbyTiles[NEARBY_TILE_KEY_LEFT] = world.getTileFrom(mode, x - 1, y) ?: Tile.NULL + nearbyTiles[NEARBY_TILE_KEY_RIGHT] = world.getTileFrom(mode, x + 1, y) ?: Tile.NULL nearbyTiles[NEARBY_TILE_KEY_UP] = world.getTileFrom(mode, x , y - 1) ?: 4906 - nearbyTiles[NEARBY_TILE_KEY_DOWN] = world.getTileFrom(mode, x , y + 1) ?: 4096 + nearbyTiles[NEARBY_TILE_KEY_DOWN] = world.getTileFrom(mode, x , y + 1) ?: Tile.NULL // try for var ret = 0 @@ -419,10 +419,10 @@ object TilesDrawer { fun getNearbyTilesInfoNonSolid(x: Int, y: Int, mode: Int): Int { val nearbyTiles = IntArray(4) - nearbyTiles[NEARBY_TILE_KEY_LEFT] = world.getTileFrom(mode, x - 1, y) ?: 4096 - nearbyTiles[NEARBY_TILE_KEY_RIGHT] = world.getTileFrom(mode, x + 1, y) ?: 4096 + nearbyTiles[NEARBY_TILE_KEY_LEFT] = world.getTileFrom(mode, x - 1, y) ?: Tile.NULL + nearbyTiles[NEARBY_TILE_KEY_RIGHT] = world.getTileFrom(mode, x + 1, y) ?: Tile.NULL nearbyTiles[NEARBY_TILE_KEY_UP] = world.getTileFrom(mode, x , y - 1) ?: 4906 - nearbyTiles[NEARBY_TILE_KEY_DOWN] = world.getTileFrom(mode, x , y + 1) ?: 4096 + nearbyTiles[NEARBY_TILE_KEY_DOWN] = world.getTileFrom(mode, x , y + 1) ?: Tile.NULL // try for var ret = 0 @@ -443,10 +443,10 @@ object TilesDrawer { fun getNearbyTilesInfoWallSticker(x: Int, y: Int): Int { val nearbyTiles = IntArray(4) val NEARBY_TILE_KEY_BACK = NEARBY_TILE_KEY_UP - nearbyTiles[NEARBY_TILE_KEY_LEFT] = world.getTileFrom(TERRAIN, x - 1, y) ?: 4096 - nearbyTiles[NEARBY_TILE_KEY_RIGHT] = world.getTileFrom(TERRAIN, x + 1, y) ?: 4096 - nearbyTiles[NEARBY_TILE_KEY_DOWN] = world.getTileFrom(TERRAIN, x , y + 1) ?: 4096 - nearbyTiles[NEARBY_TILE_KEY_BACK] = world.getTileFrom(WALL, x , y) ?: 4096 + nearbyTiles[NEARBY_TILE_KEY_LEFT] = world.getTileFrom(TERRAIN, x - 1, y) ?: Tile.NULL + nearbyTiles[NEARBY_TILE_KEY_RIGHT] = world.getTileFrom(TERRAIN, x + 1, y) ?: Tile.NULL + nearbyTiles[NEARBY_TILE_KEY_DOWN] = world.getTileFrom(TERRAIN, x , y + 1) ?: Tile.NULL + nearbyTiles[NEARBY_TILE_KEY_BACK] = world.getTileFrom(WALL, x , y) ?: Tile.NULL try { if (TileCodex[nearbyTiles[NEARBY_TILE_KEY_DOWN]].isSolid) @@ -476,8 +476,8 @@ object TilesDrawer { fun getNearbyTilesInfoPlatform(x: Int, y: Int): Int { val nearbyTiles = IntArray(4) - nearbyTiles[NEARBY_TILE_KEY_LEFT] = world.getTileFrom(TERRAIN, x - 1, y) ?: 4096 - nearbyTiles[NEARBY_TILE_KEY_RIGHT] = world.getTileFrom(TERRAIN, x + 1, y) ?: 4096 + nearbyTiles[NEARBY_TILE_KEY_LEFT] = world.getTileFrom(TERRAIN, x - 1, y) ?: Tile.NULL + nearbyTiles[NEARBY_TILE_KEY_RIGHT] = world.getTileFrom(TERRAIN, x + 1, y) ?: Tile.NULL if ((TileCodex[nearbyTiles[NEARBY_TILE_KEY_LEFT]].isSolid && TileCodex[nearbyTiles[NEARBY_TILE_KEY_RIGHT]].isSolid) || diff --git a/src/net/torvald/terrarum/realestate/RealEstateUtility.kt b/src/net/torvald/terrarum/realestate/RealEstateUtility.kt index accb20635..0d1755840 100644 --- a/src/net/torvald/terrarum/realestate/RealEstateUtility.kt +++ b/src/net/torvald/terrarum/realestate/RealEstateUtility.kt @@ -2,21 +2,22 @@ package net.torvald.terrarum.realestate import net.torvald.terrarum.Terrarum import net.torvald.terrarum.gameactors.faction.FactionCodex +import net.torvald.terrarum.gameworld.TileAddress /** * Created by minjaesong on 16-03-27. */ object RealEstateUtility { - fun getAbsoluteTileNumber(x: Int, y: Int): Long = + fun getAbsoluteTileNumber(x: Int, y: Int): TileAddress = (Terrarum.ingame!!.world.width * y).toLong() + x - fun resolveAbsoluteTileNumber(t: Long): Pair = + fun resolveAbsoluteTileNumber(t: TileAddress): Pair = Pair((t % Terrarum.ingame!!.world.width).toInt(), (t / Terrarum.ingame!!.world.width).toInt()) /** * Get owner ID as an Actor/Faction */ - fun resolveOwner(id: Long): Any = + fun resolveOwner(id: TileAddress): Any = if (id < 0x80000000L) Terrarum.ingame!!.getActorByID(id.toInt()) else diff --git a/src/net/torvald/terrarum/tileproperties/Tile.kt b/src/net/torvald/terrarum/tileproperties/Tile.kt index 892038fdd..10c891072 100644 --- a/src/net/torvald/terrarum/tileproperties/Tile.kt +++ b/src/net/torvald/terrarum/tileproperties/Tile.kt @@ -150,5 +150,5 @@ object Tile { val LAVA_15 = TileCodex.idDamageToIndex(254, 14) val LAVA = TileCodex.idDamageToIndex(254, 15) - val NULL = 4096 + val NULL = -1 } diff --git a/src/net/torvald/terrarum/tileproperties/TileCodex.kt b/src/net/torvald/terrarum/tileproperties/TileCodex.kt index ac9cd5700..f94561b7b 100644 --- a/src/net/torvald/terrarum/tileproperties/TileCodex.kt +++ b/src/net/torvald/terrarum/tileproperties/TileCodex.kt @@ -18,8 +18,10 @@ object TileCodex { const val TILE_UNIQUE_MAX = MapLayer.RANGE * PairedMapLayer.RANGE + private val nullProp = TileProp() + init { - tileProps = Array(TILE_UNIQUE_MAX + 1, { i -> TileProp() }) + tileProps = Array(TILE_UNIQUE_MAX * 2, { i -> TileProp() }) for (i in tileProps.indices) { tileProps[i] = TileProp() @@ -31,8 +33,15 @@ object TileCodex { println("[TileCodex] Building tile properties table") - records.forEach { setProp( - tileProps[idDamageToIndex(intVal(it, "id"), intVal(it, "dmg"))], it) + records.forEach { + if (intVal(it, "dmg") == -1) { + setProp(nullProp, it) + } + else { + setProp( + tileProps[idDamageToIndex(intVal(it, "id"), intVal(it, "dmg"))], it + ) + } } } catch (e: IOException) { @@ -53,14 +62,16 @@ object TileCodex { } operator fun get(rawIndex: Int?): TileProp { + if (rawIndex == null || rawIndex == Tile.NULL) { + return nullProp + } + try { - tileProps[rawIndex ?: Tile.NULL].id + return tileProps[rawIndex] } catch (e: NullPointerException) { throw NullPointerException("Tile prop with raw id $rawIndex does not exist.") } - - return tileProps[rawIndex ?: Tile.NULL] } private fun setProp(prop: TileProp, record: CSVRecord) { diff --git a/src/net/torvald/terrarum/tileproperties/TilePropCSV.kt b/src/net/torvald/terrarum/tileproperties/TilePropCSV.kt index 65486f011..bd9a5a81e 100644 --- a/src/net/torvald/terrarum/tileproperties/TilePropCSV.kt +++ b/src/net/torvald/terrarum/tileproperties/TilePropCSV.kt @@ -135,7 +135,7 @@ object TilePropCSV { "255"; "13";"TILE_WATER" ; "27282445"; "100";"1000";"watr"; "1"; "0"; "0"; "0"; "N/A"; "N/A"; "0"; "0"; "16"; "0";"16" "255"; "14";"TILE_WATER" ; "27282445"; "100";"1000";"watr"; "1"; "0"; "0"; "0"; "N/A"; "N/A"; "0"; "0"; "16"; "0";"16" "255"; "15";"TILE_WATER" ; "27282445"; "100";"1000";"watr"; "1"; "0"; "0"; "0"; "N/A"; "N/A"; "0"; "0"; "16"; "0";"16" -"256"; "0";"TILE_NULL" ;"1073741823"; "-1";"2600";"null"; "0"; "0"; "1"; "0"; "N/A"; "N/A"; "0"; "0"; "N/A"; "0";"16" + "0"; "-1";"TILE_NULL" ;"1073741823"; "-1";"2600";"null"; "0"; "0"; "1"; "0"; "N/A"; "N/A"; "0"; "0"; "N/A"; "0";"16" ## Notes ## diff --git a/src/net/torvald/terrarum/ui/UICanvas.kt b/src/net/torvald/terrarum/ui/UICanvas.kt index be3591270..145260fca 100644 --- a/src/net/torvald/terrarum/ui/UICanvas.kt +++ b/src/net/torvald/terrarum/ui/UICanvas.kt @@ -1,6 +1,9 @@ package net.torvald.terrarum.ui +import net.torvald.point.Point2d import net.torvald.terrarum.Millisec +import net.torvald.terrarum.Terrarum +import net.torvald.terrarum.gameactors.roundInt import org.newdawn.slick.GameContainer import org.newdawn.slick.Graphics import org.newdawn.slick.Input @@ -57,21 +60,86 @@ interface UICanvas { fun doOpeningFade(handler: UIHandler?, openCloseTime: Int) { handler!!.opacity = handler.openCloseCounter.toFloat() / openCloseTime } - fun doClosingFade(handler: UIHandler?, openCloseTime: Int) { handler!!.opacity = (openCloseTime - handler.openCloseCounter.toFloat()) / openCloseTime } - fun endOpeningFade(handler: UIHandler?) { handler!!.opacity = 1f } - fun endClosingFade(handler: UIHandler?) { handler!!.opacity = 0f } - // TODO add drawer slide in/out (quadratic) + + fun doOpeningPopOut(handler: UIHandler?, openCloseTime: Int, position: Position) { + when (position) { + Position.LEFT -> handler!!.posX = Movement.fastPullOut( + handler.openCloseCounter.toFloat() / openCloseTime, + -handler.UI.width.toFloat(), + 0f + ).roundInt() + Position.TOP -> handler!!.posY = Movement.fastPullOut( + handler.openCloseCounter.toFloat() / openCloseTime, + -handler.UI.height.toFloat(), + 0f + ).roundInt() + Position.RIGHT -> handler!!.posX = Movement.fastPullOut( + handler.openCloseCounter.toFloat() / openCloseTime, + Terrarum.WIDTH.toFloat(), + Terrarum.WIDTH - handler.UI.width.toFloat() + ).roundInt() + Position.BOTTOM -> handler!!.posY = Movement.fastPullOut( + handler.openCloseCounter.toFloat() / openCloseTime, + Terrarum.HEIGHT.toFloat(), + Terrarum.HEIGHT - handler.UI.height.toFloat() + ).roundInt() + } + } + fun doClosingPopOut(handler: UIHandler?, openCloseTime: Int, position: Position) { + when (position) { + Position.LEFT -> handler!!.posX = Movement.fastPullOut( + handler.openCloseCounter.toFloat() / openCloseTime, + 0f, + -handler.UI.width.toFloat() + ).roundInt() + Position.TOP -> handler!!.posY = Movement.fastPullOut( + handler.openCloseCounter.toFloat() / openCloseTime, + 0f, + -handler.UI.height.toFloat() + ).roundInt() + Position.RIGHT -> handler!!.posX = Movement.fastPullOut( + handler.openCloseCounter.toFloat() / openCloseTime, + Terrarum.WIDTH - handler.UI.width.toFloat(), + Terrarum.WIDTH.toFloat() + ).roundInt() + Position.BOTTOM -> handler!!.posY = Movement.fastPullOut( + handler.openCloseCounter.toFloat() / openCloseTime, + Terrarum.HEIGHT - handler.UI.height.toFloat(), + Terrarum.HEIGHT.toFloat() + ).roundInt() + } + } + fun endOpeningPopOut(handler: UIHandler?, position: Position) { + when (position) { + Position.LEFT -> handler!!.posX = 0 + Position.TOP -> handler!!.posY = 0 + Position.RIGHT -> handler!!.posX = Terrarum.WIDTH - handler.UI.width + Position.BOTTOM -> handler!!.posY = Terrarum.HEIGHT - handler.UI.height + } + } + fun endClosingPopOut(handler: UIHandler?, position: Position) { + when (position) { + Position.LEFT -> handler!!.posX = -handler.UI.width + Position.TOP -> handler!!.posY = -handler.UI.height + Position.RIGHT -> handler!!.posX = Terrarum.WIDTH + Position.BOTTOM -> handler!!.posY = Terrarum.HEIGHT + } + } // TODO add blackboard take in/out (sinusoidal) + + enum class Position { + LEFT, RIGHT, TOP, BOTTOM + } } } diff --git a/src/net/torvald/terrarum/ui/UIInventory.kt b/src/net/torvald/terrarum/ui/UIInventory.kt index df1280c14..701aaf859 100644 --- a/src/net/torvald/terrarum/ui/UIInventory.kt +++ b/src/net/torvald/terrarum/ui/UIInventory.kt @@ -158,7 +158,7 @@ class UIInventory( // filter items inventory?.forEach { - if (it.item.category == filter || filter == "__all__") + if (it.item.inventoryCategory == filter || filter == "__all__") inventorySortList.add(it) } @@ -295,27 +295,20 @@ class UIInventory( } override fun doOpening(gc: GameContainer, delta: Int) { - handler!!.posX = Movement.fastPullOut( - handler!!.openCloseCounter.toFloat() / openCloseTime, - -width.toFloat(), - 0f - ).roundInt() + UICanvas.doOpeningPopOut(handler, openCloseTime, UICanvas.Companion.Position.LEFT) } override fun doClosing(gc: GameContainer, delta: Int) { - handler!!.posX = Movement.fastPullOut( - handler!!.openCloseCounter.toFloat() / openCloseTime, - 0f, - -width.toFloat() - ).roundInt() + UICanvas.doClosingPopOut(handler, openCloseTime, UICanvas.Companion.Position.LEFT) + } override fun endOpening(gc: GameContainer, delta: Int) { - handler!!.posX = 0 + UICanvas.endOpeningPopOut(handler, UICanvas.Companion.Position.LEFT) } override fun endClosing(gc: GameContainer, delta: Int) { - handler!!.posX = -width + UICanvas.endClosingPopOut(handler, UICanvas.Companion.Position.LEFT) } override fun keyPressed(key: Int, c: Char) { diff --git a/src/net/torvald/terrarum/virtualcomputer/luaapi/FilesystemTEVD.kt b/src/net/torvald/terrarum/virtualcomputer/luaapi/FilesystemTEVD.kt index da17e7f97..05bda243d 100644 --- a/src/net/torvald/terrarum/virtualcomputer/luaapi/FilesystemTEVD.kt +++ b/src/net/torvald/terrarum/virtualcomputer/luaapi/FilesystemTEVD.kt @@ -94,7 +94,7 @@ internal class Filesystem(globals: Globals, computer: TerrarumComputer) { path.dropMount() - return VDUtil.getFile(disk, path)?.file + return VDUtil.getFile(disk, path) } /** @@ -201,7 +201,7 @@ internal class Filesystem(globals: Globals, computer: TerrarumComputer) { if (file!!.contents is EntryFile) return LuaValue.valueOf(file.contents.getSizePure().toInt()) else if (file.contents is EntryDirectory) - return LuaValue.valueOf(file.contents.entries.size) + return LuaValue.valueOf(file.contents.entryCount) } catch (e: KotlinNullPointerException) { } @@ -279,12 +279,12 @@ internal class Filesystem(globals: Globals, computer: TerrarumComputer) { val file = VDUtil.getFile(disk1, pathFrom)!! try { - VDUtil.addFile(disk2, pathTo.getParent(), file.file) + VDUtil.addFile(disk2, pathTo.getParent(), file) } catch (e: FileNotFoundException) { // roll back delete on disk2 if (oldFile != null) { - VDUtil.addFile(disk2, oldFile.parent.entryID, oldFile.file) + VDUtil.addFile(disk2, oldFile.parentEntryID, oldFile) throw FileNotFoundException("No such destination") } } diff --git a/src/net/torvald/terrarum/virtualcomputer/tvd/VDUtil.kt b/src/net/torvald/terrarum/virtualcomputer/tvd/VDUtil.kt index 84c42fc2c..1f242d19b 100644 --- a/src/net/torvald/terrarum/virtualcomputer/tvd/VDUtil.kt +++ b/src/net/torvald/terrarum/virtualcomputer/tvd/VDUtil.kt @@ -41,7 +41,7 @@ object VDUtil { unsanitisedHierarchy.removeAt(0) // removes tail slash if (unsanitisedHierarchy.size > 0 && - unsanitisedHierarchy[unsanitisedHierarchy.lastIndex].isEmpty()) + unsanitisedHierarchy[unsanitisedHierarchy.lastIndex].isEmpty()) unsanitisedHierarchy.removeAt(unsanitisedHierarchy.lastIndex) unsanitisedHierarchy.forEach { @@ -202,7 +202,7 @@ object VDUtil { val calculatedCRC = diskEntry.hashCode() val crcMsg = "CRC failed: expected ${entryCRC.toHex()}, got ${calculatedCRC.toHex()}\n" + - "at file \"${diskEntry.getFilenameString(charset)}\" (entry ID ${diskEntry.entryID})" + "at file \"${diskEntry.getFilenameString(charset)}\" (entry ID ${diskEntry.entryID})" if (calculatedCRC != entryCRC) { if (crcWarnLevel == Level.SEVERE) @@ -243,7 +243,7 @@ object VDUtil { throw IllegalArgumentException("The entry is not directory") val entriesList = ArrayList() - dirToSearch.contents.entries.forEach { + dirToSearch.contents.forEach { val entry = disk.entries[it] if (entry != null) entriesList.add(entry) } @@ -267,7 +267,7 @@ object VDUtil { * Search a entry using path * @return Pair of , or null if not found */ - fun getFile(disk: VirtualDisk, path: VDPath): EntrySearchResult? { + fun getFile(disk: VirtualDisk, path: VDPath): DiskEntry? { val searchHierarchy = ArrayList() fun getCurrentEntry(): DiskEntry = searchHierarchy.last() //var currentDirectory = disk.root @@ -276,10 +276,7 @@ object VDUtil { // path of root if (path.hierarchy.size == 0) { - return EntrySearchResult( - disk.entries[0]!!, - disk.entries[0]!! - ) + return disk.entries[0]!! } try { @@ -310,10 +307,7 @@ object VDUtil { } // file found - return EntrySearchResult( - searchHierarchy[searchHierarchy.lastIndex], - searchHierarchy[searchHierarchy.lastIndex - 1] - ) + return searchHierarchy[searchHierarchy.lastIndex] } /** @@ -323,12 +317,12 @@ object VDUtil { */ private fun DiskEntry.getAsNormalFile(disk: VirtualDisk): EntryFile = this.contents as? EntryFile ?: - if (this.contents is EntryDirectory) - throw RuntimeException("this is directory") - else if (this.contents is EntrySymlink) - disk.entries[this.contents.target]!!.getAsNormalFile(disk) - else - throw RuntimeException("Unknown entry type") + if (this.contents is EntryDirectory) + throw RuntimeException("this is directory") + else if (this.contents is EntrySymlink) + disk.entries[this.contents.target]!!.getAsNormalFile(disk) + else + throw RuntimeException("Unknown entry type") /** * SYNOPSIS disk.getFile("bin/msh.lua")!!.first.getAsNormalFile(disk) * @@ -336,18 +330,18 @@ object VDUtil { */ private fun DiskEntry.getAsDirectory(disk: VirtualDisk): EntryDirectory = this.contents as? EntryDirectory ?: - if (this.contents is EntrySymlink) - disk.entries[this.contents.target]!!.getAsDirectory(disk) - else if (this.contents is EntryFile) - throw RuntimeException("this is not directory") - else - throw RuntimeException("Unknown entry type") + if (this.contents is EntrySymlink) + disk.entries[this.contents.target]!!.getAsDirectory(disk) + else if (this.contents is EntryFile) + throw RuntimeException("this is not directory") + else + throw RuntimeException("Unknown entry type") /** * Search for the file and returns a instance of normal file. */ fun getAsNormalFile(disk: VirtualDisk, path: VDPath) = - getFile(disk, path)!!.file.getAsNormalFile(disk) + getFile(disk, path)!!.getAsNormalFile(disk) /** * Fetch the file and returns a instance of normal file. */ @@ -357,7 +351,7 @@ object VDUtil { * Search for the file and returns a instance of directory. */ fun getAsDirectory(disk: VirtualDisk, path: VDPath) = - getFile(disk, path)!!.file.getAsDirectory(disk) + getFile(disk, path)!!.getAsDirectory(disk) /** * Fetch the file and returns a instance of directory. */ @@ -367,11 +361,8 @@ object VDUtil { * Deletes file on the disk safely. */ fun deleteFile(disk: VirtualDisk, path: VDPath) { - disk.checkReadOnly() - val fileSearchResult = getFile(disk, path)!! - - return deleteFile(disk, fileSearchResult.file.entryID) + return deleteFile(disk, fileSearchResult.entryID) } /** * Deletes file on the disk safely. @@ -386,29 +377,25 @@ object VDUtil { } val parentID = file.parentEntryID - val parentDir = disk.entries[parentID] + val parentDir = getAsDirectory(disk, parentID) fun rollback() { if (!disk.entries.contains(targetID)) { disk.entries[targetID] = file } - if (!(parentDir!!.contents as EntryDirectory).entries.contains(targetID)) { - (parentDir.contents as EntryDirectory).entries.add(targetID) + if (!parentDir.contains(targetID)) { + parentDir.add(targetID) } } - if (parentDir == null || parentDir.contents !is EntryDirectory) { - throw FileNotFoundException("No such parent directory") - } // check if directory "parentID" has "targetID" in the first place - else if (!directoryContains(disk, parentID, targetID)) { + if (!directoryContains(disk, parentID, targetID)) { throw FileNotFoundException("No such file to delete") } else if (targetID == 0) { throw IOException("Cannot delete root file system") } - else if (file.contents is EntryDirectory && file.contents.entries.size > 0) { - //throw IOException("Cannot delete directory that contains something") + else if (file.contents is EntryDirectory && file.contents.entryCount > 0) { deleteDirRecurse(disk, targetID) } else { @@ -416,7 +403,7 @@ object VDUtil { // delete file record disk.entries.remove(targetID) // unlist file from parent directly - (disk.entries[parentID]!!.contents as EntryDirectory).entries.remove(targetID) + parentDir.remove(targetID) } catch (e: Exception) { rollback() @@ -428,7 +415,7 @@ object VDUtil { * Changes the name of the entry. */ fun renameFile(disk: VirtualDisk, path: VDPath, newName: String, charset: Charset) { - val file = getFile(disk, path)?.file + val file = getFile(disk, path) if (file != null) { file.filename = newName.sanitisePath().toEntryName(DiskEntry.NAME_LENGTH, charset) @@ -451,23 +438,12 @@ object VDUtil { } } /** - * Add file to the specified directory. ParentID of the file will be overwritten. + * Add file to the specified directory. + * The file will get new EntryID and its ParentID will be overwritten. */ fun addFile(disk: VirtualDisk, parentPath: VDPath, file: DiskEntry) { - disk.checkReadOnly() - disk.checkCapacity(file.serialisedSize) - - try { - val parentID = getFile(disk, parentPath)!!.file.entryID - // add record to the directory - getAsDirectory(disk, parentPath).entries.add(file.entryID) - // add entry on the disk - disk.entries[file.entryID] = file - file.parentEntryID = parentID - } - catch (e: KotlinNullPointerException) { - throw FileNotFoundException("No such directory") - } + val targetDirID = getFile(disk, parentPath)!!.entryID + return addFile(disk, targetDirID, file) } /** * Add file to the specified directory. ParentID of the file will be overwritten. @@ -477,10 +453,13 @@ object VDUtil { disk.checkCapacity(file.serialisedSize) try { + // generate new ID for the file + file.entryID = disk.generateUniqueID() // add record to the directory - getAsDirectory(disk, directoryID).entries.add(file.entryID) + getAsDirectory(disk, directoryID).add(file.entryID) // add entry on the disk disk.entries[file.entryID] = file + // make this boy recognise his new parent file.parentEntryID = directoryID } catch (e: KotlinNullPointerException) { @@ -491,28 +470,8 @@ object VDUtil { * Add subdirectory to the specified directory. */ fun addDir(disk: VirtualDisk, parentPath: VDPath, name: ByteArray) { - disk.checkReadOnly() - disk.checkCapacity(EntryDirectory.NEW_ENTRY_SIZE) - - val newID = disk.generateUniqueID() - - try { - val parentID = getFile(disk, parentPath)!!.file.entryID - // add record to the directory - getAsDirectory(disk, parentPath).entries.add(newID) - // add entry on the disk - disk.entries[newID] = DiskEntry( - newID, - parentID, - name, - currentUnixtime, - currentUnixtime, - EntryDirectory() - ) - } - catch (e: KotlinNullPointerException) { - throw FileNotFoundException("No such directory") - } + val parentID = getFile(disk, parentPath)!!.entryID + return addDir(disk, parentID, name) } /** * Add file to the specified directory. @@ -525,7 +484,7 @@ object VDUtil { try { // add record to the directory - getAsDirectory(disk, directoryID).entries.add(newID) + getAsDirectory(disk, directoryID).add(newID) // add entry on the disk disk.entries[newID] = DiskEntry( newID, @@ -553,7 +512,7 @@ object VDUtil { } // recurse else { - entry.contents.entries.forEach { + entry.contents.forEach { entriesToDelete.add(entry.entryID) recurse1(disk.entries[it]) } @@ -562,7 +521,7 @@ object VDUtil { val entry = disk.entries[directoryID] if (entry != null && entry.contents is EntryDirectory) { - entry.contents.entries.forEach { + entry.contents.forEach { entriesToDelete.add(directoryID) recurse1(disk.entries[it]) } @@ -630,12 +589,10 @@ object VDUtil { fun moveFile(disk1: VirtualDisk, fromPath: VDPath, disk2: VirtualDisk, toPath: VDPath) { val file = getFile(disk1, fromPath) - if (file != null) { - if (file.file.contents is EntryDirectory) { - throw IOException("Cannot move directory") - } + // checking readOnly is redundant here - disk2.checkCapacity(file.file.contents.getSizeEntry()) + if (file != null) { + disk2.checkCapacity(file.contents.getSizeEntry()) try { deleteFile(disk2, toPath) @@ -644,11 +601,11 @@ object VDUtil { deleteFile(disk1, fromPath) // any uncaught no_from_file will be caught here try { - addFile(disk2, toPath.getParent(), file.file) + addFile(disk2, toPath.getParent(), file) } catch (e: FileNotFoundException) { // roll back delete on disk1 - addFile(disk1, file.parent.entryID, file.file) + addFile(disk1, file.parentEntryID, file) throw FileNotFoundException("No such destination") } } @@ -740,7 +697,6 @@ object VDUtil { val path1 = this.replace('\\', '/') return path1 } - data class EntrySearchResult(val file: DiskEntry, val parent: DiskEntry) fun resolveIfSymlink(disk: VirtualDisk, indexNumber: EntryID, recurse: Boolean = false): DiskEntry { var entry: DiskEntry? = disk.entries[indexNumber] @@ -769,7 +725,7 @@ object VDUtil { throw FileNotFoundException("Not a directory") } else { - return dir.contents.entries.contains(targetID) + return dir.contents.contains(targetID) } } @@ -784,11 +740,16 @@ object VDUtil { return disk.entries.filter { disk.entries[it.value.parentEntryID] == null }.keys.toList() } + /** + * Searches for null-pointing entries (phantoms) within every directory. + * + * @return List of search results, which is Pair(directory that contains null pointer, null pointer) + */ fun gcSearchPhantomBaby(disk: VirtualDisk): List> { // Pair val phantoms = ArrayList>() disk.entries.filter { it.value.contents is EntryDirectory }.values.forEach { directory -> - (directory.contents as EntryDirectory).entries.forEach { dirEntryID -> + (directory.contents as EntryDirectory).forEach { dirEntryID -> if (disk.entries[dirEntryID] == null) { phantoms.add(Pair(directory.entryID, dirEntryID)) } @@ -811,7 +772,7 @@ object VDUtil { fun gcDumpAll(disk: VirtualDisk) { try { gcSearchPhantomBaby(disk).forEach { - getAsDirectory(disk, it.first).entries.remove(it.second) + getAsDirectory(disk, it.first).remove(it.second) } gcSearchOrphan(disk).forEach { disk.entries.remove(it) diff --git a/src/net/torvald/terrarum/virtualcomputer/tvd/VirtualDisk.kt b/src/net/torvald/terrarum/virtualcomputer/tvd/VirtualDisk.kt index f062d23f5..0fa599e70 100644 --- a/src/net/torvald/terrarum/virtualcomputer/tvd/VirtualDisk.kt +++ b/src/net/torvald/terrarum/virtualcomputer/tvd/VirtualDisk.kt @@ -1,5 +1,6 @@ package net.torvald.terrarum.virtualcomputer.tvd +import java.io.IOException import java.nio.charset.Charset import java.util.* import java.util.function.Consumer @@ -182,10 +183,30 @@ class EntryFile(var bytes: ByteArray64) : DiskEntryContent { return buffer } } -class EntryDirectory(val entries: ArrayList = ArrayList()) : DiskEntryContent { +class EntryDirectory(private val entries: ArrayList = ArrayList()) : DiskEntryContent { override fun getSizePure() = entries.size * 4L override fun getSizeEntry() = getSizePure() + 2 + private fun checkCapacity(toAdd: Int = 1) { + if (entries.size + toAdd > 65535) + throw IOException("Directory entries limit exceeded.") + } + + fun add(entryID: EntryID) { + checkCapacity() + entries.add(entryID) + } + + fun remove(entryID: EntryID) { + entries.removeAt(entryID) + } + + fun contains(entryID: EntryID) = entries.contains(entryID) + + fun forEach(consumer: (EntryID) -> Unit) = entries.forEach(consumer) + + val entryCount: Int + get() = entries.size override fun serialize(): AppendableByteBuffer { val buffer = AppendableByteBuffer(getSizeEntry()) diff --git a/work_files/Attack momentum calculator.xlsx b/work_files/Attack momentum calculator.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..e8cf48424520552033c99c128e80d350e481d2b7 GIT binary patch literal 30623 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 WBj9g2OyDrY2l51R^x^^Ee*F)Jem-vi literal 0 HcmV?d00001 diff --git a/work_files/Pickaxe Power.xlsx b/work_files/Pickaxe Power.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..d3735172d928422cd380688e1a2ed1d12c07a257 GIT binary patch literal 37591 zcmeFZ^P4SOvn5=%ZQHhOV;6VXwr$&0yNq47z00<3+v+;!z1?s3chCL$54fE_tX%ob zT+hlmX2ggwBjQN~X(hDDZpTStIHlxFMHMLJAE)yz^_H%mVr zT^^lNQ!_x72ic>goC6G3sa%n=C-rbXM;FSeff<9&HwjGi5a`I)L@iX?{G>K?em2WrUS z$eC`VOE)F1AT@=JNLaUsY}Z}qPAuK|;^f8X9f7cLqL9j>&|2ap^ZSYMzIp2~P2mka zApE@j%dg|-XE83K3(oBmE?!c|Vq!oHcrXT6OtNXZLn#o2=6IJowsyagWn3;5gxF}1 z%}tqDPw4qx?12oTsksEtH_~aq_ts_|d>={9h~c>e+CvsRB)!lpT34!1zIE0n;*+qP z^H)U)Q|%r^9Pxe=V%UnUlUA#Lx`A}l`Oun5Z8kB zep@s4*Cclw*bA{01HOFhhn*bFZek9PrK`EJ#~0dLil~mNV_**EW}cm#Gf^kKR>;XY z1xLUTXbxNfth01-0tm%lR~=s%CjzW1hGueBQ1j61JlP29zJLG#Uthog3jYVGG^#QX z-+#M`%r|F1f0N2j2V*Nodb+2pVs? zzviH<#-_n@72tx9@*RU1g!wZ(G zvKgm&jX{nB7m@o?689goEBkUjm02trExLMH~Iq18Z+n753&o4}Wh2IL5wU|r>gb!59 z&2|h4iJD!BP6_X_)zSuh21^+MR<^p0p!21rK}lD2@3BYF%$qF7K~pf7fDe~hHeR{e zcz2am#@@Uq9|Mg;5qfbac#{OKEa$xx|6!FujV%`?TfwG=A4^A~kW}GMjEHMfFv2kC$<0PTy zwsIf{{Gkk?q+Qwvr14r5@e|p&)w;X5axomo3S>-k&Lj~FPO7&4+8jx14%yXc&PI7+ zM1Ah6`wfMh2#CyTXR^8jb@eI|BpDTVzlz))6-kinYn1-H2!@oF>MCKbl|l|FV&^$ zN|^a6u2p0MZ+7E(EtJRS5cj$<1s3KB)j3HCdK)GeVhc?dzgPQTtmta%U}<1$Yx&nw|4)Vl{FYna z_x|@jI+CU=z8PZhDzGzf#@jx@MhDZ`V;SSV%^6dK-lVy>@{eOnIYa@$|i1A`;tU;Q{ z&lr$FmcSJ?sD6n=Va0Qz1eod#;$aig3{D!iIDDra@wwXY1_BJB zCua7jq%Luc8uA=aQN-VjH?Oc|!r2}fdDI&F|b zpxz0l4lnb;G#n4Eeo{o_Ieqw!u_C|A@v$8 zMS>m)yNhu^Qi~9-u|zP}$1Q2H{nMTXidVtF1!;lFYH*zI1D{{F3;NYm(Wh~?*9ALZ zHIzKoCrI5iu`7$4OzQE2VL?^9=e-6mD;ud->^xbZB|g zhKb6vzcv82RN)37=&KKPt`S|>Q7{U$!cQ}HCgG*R=8l#cmokx%9a+ZPj^}xv$ZYeQ z3()IlB8P`?x|bRHy&d<4vxM{#e+hM*CEzfPr4QG3zt0}jg;n)!8a^Wy^8aHLIvZHb zsRjc8D5C@bfc=*dIXbyp89V;PN9R~;F{>Q+-bEjw6jw5IB-&yEtUX4}O3hl@Nd}L09iM8&ZJQWbyS7<~X)rSl1 z7M9=d5uCt^IVj6pi-wd%1t^=S*vau~?+1k)jLoacNt-!8r zgM4b#v54X5≪XD@EnY01V7KSht%Fgpm~Y*1kDS&BB7fL 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�rS?RZ5iXC$`1%A~!T-@Mt@i)&u4#KcJf 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�%bw4err~1p*A!&e!ed(*8tK&rTcm2doC71HX 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 PC>I!p!N4G{Ac66JTcSCq literal 0 HcmV?d00001