diff --git a/REFERENCING.md b/REFERENCING.md index b22fa171c..3b5252d43 100644 --- a/REFERENCING.md +++ b/REFERENCING.md @@ -1,17 +1,42 @@ +## Prefix-ID Referencing + +Every blocks and items have Prefix-ID Referencing scheme, which is defined as follows: + +```@:``` + +where Prefix is predefined (see below), Integer ID is arbitrarily chosen within a domain. + +### Prefixes +|Name|Description| +|----|-----------| +|wall|Wall, only used by the Inventory to differentiate walls from blocks (therefore wall shares same "ID Space" with blocks/fluids/wires)| +|item|Item (Static), uses different "ID Space" with blocks/walls/fluids/wires| + +Notes: +- BlockCodex and ItemCodex will not store prefix part of the ID, as blocks and walls are identical in properties +- Wires and Fluids use the same "ID Space" as the tiles; they just happened to exclusive to their own layers. + This simplifies many things e.g. only one TileID-to-AtlasTileNumber map is needed and the renderer will + greatly benefit from it. + +### Predefined Modnames + +|Name|Description| +|----|-----------| +|dyn|Dynamic Item| +|actor|Actor As an Item. Integer ID is identical to the actor's Reference ID| +|virt|Virtual Tile Number| + +### Integer ID Domains + |Range|Description| |-----|-----------| -|0..65535|Tiles (65536 possible)| -|65536..131071|Walls (65536 possible)| -|131072..135167|Wires (4096 possible)| -|135168..0x0F_FFFF|Items (static) (1M possible)| -|0x10_0000..0x0FFF_FFFF|Items (dynamic\*) (267M possible)| -|0x1000_0000..0x7FFF_FFFF|Actors (1879M possible)| -|-2..-1048576|Virtual Tiles| -|-2147483648..-1048577 (all negative numbers)|Faction (2147M possible)| +|1..2147483647|Integer ID for dynamic items| +|0x1000_0000..0x7FFF_FFFF|Reference ID for Actors (1879M possible)| +|1..2147483647|Integer ID for virtual tiles| * dynamic items have own properties that will persist through savegame. -Actors range in-depth +Actor range in-depth |Range|Description| |-----|-----------| diff --git a/assets/graphics/blocks/init.tga b/assets/graphics/blocks/init.tga index b1ecf0745..bbbfdde21 100644 --- a/assets/graphics/blocks/init.tga +++ b/assets/graphics/blocks/init.tga @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:678f5a624e5f348863b195aa2b2e8a63f94608bee327d1021a441551ad1669b1 -size 16428 +oid sha256:4a920ad9d970b004d54293cbef244bff987513054f2bb272fa99635a4d9e7418 +size 16402 diff --git a/assets/mods/basegame/blocks/0.tga b/assets/mods/basegame/blocks/0.tga new file mode 100644 index 000000000..eba0040b7 --- /dev/null +++ b/assets/mods/basegame/blocks/0.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aa177db29d3567b79eea0effaa62e087c707b0178da94f95f963c35567624d0b +size 1068 diff --git a/assets/mods/basegame/blocks/_8192.tga b/assets/mods/basegame/blocks/_8192.tga new file mode 100644 index 000000000..9a2635e0f --- /dev/null +++ b/assets/mods/basegame/blocks/_8192.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5b982f8deeadc1f32ba38bff9e43f3261865e7684de0abde31fff69c3c6c00f9 +size 32786 diff --git a/assets/mods/basegame/blocks/_8193.tga b/assets/mods/basegame/blocks/_8193.tga new file mode 100644 index 000000000..f44843bbc --- /dev/null +++ b/assets/mods/basegame/blocks/_8193.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cc9a00c95f5cfb94403a59ffde45be48c4d2aa08e7153e98fb0679b4fc8fcca2 +size 32786 diff --git a/assets/mods/basegame/blocks/_8194.tga b/assets/mods/basegame/blocks/_8194.tga new file mode 100644 index 000000000..56378d1ee --- /dev/null +++ b/assets/mods/basegame/blocks/_8194.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:18a89e333e12d09f55db8f4f155df65a8b5fe3696be19cd9adeb15d11f0fb5d3 +size 32786 diff --git a/assets/mods/basegame/blocks/_8195.tga b/assets/mods/basegame/blocks/_8195.tga new file mode 100644 index 000000000..87a138f6e --- /dev/null +++ b/assets/mods/basegame/blocks/_8195.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7b82523a6f81b036afd2fa520a96f741e38247983cd47a404ad37f80946a046a +size 131090 diff --git a/assets/mods/basegame/blocks/blocks.csv b/assets/mods/basegame/blocks/blocks.csv index 78787630c..bb1de1918 100644 --- a/assets/mods/basegame/blocks/blocks.csv +++ b/assets/mods/basegame/blocks/blocks.csv @@ -1,6 +1,5 @@ "id";"drop";"name";"shdr";"shdg";"shdb";"shduv";"str";"dsty";"mate";"solid";"plat";"wall";"grav";"dlfn";"fv";"fr";"lumr";"lumg";"lumb";"lumuv";"colour";"vscs" "0";"0";"BLOCK_AIR";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"0";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A" -"1";"1";"BLOCK_MIASMA";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"0";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A" "16";"17";"BLOCK_STONE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"0";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A" "17";"17";"BLOCK_STONE_QUARRIED";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"0";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A" "18";"18";"BLOCK_STONE_TILE_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"0";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A" diff --git a/assets/mods/basegame/blocks/wires.csv b/assets/mods/basegame/blocks/wires.csv new file mode 100644 index 000000000..e0cb01472 --- /dev/null +++ b/assets/mods/basegame/blocks/wires.csv @@ -0,0 +1,12 @@ +"id";"drop";"name";"accept";"inputcount";"inputtype";"outputtype" +"8192";"8192";"WIRE_RED";"digital_bit";"N/A";"N/A";"N/A" +"8193";"8193";"WIRE_GREEN";"digital_bit";"N/A";"N/A";"N/A" +"8194";"8194";"WIRE_BLUE";"digital_bit";"N/A";"N/A";"N/A" +"8195";"8195";"WIRE_BUNDLE";"digital_3bits";"N/A";"N/A";"N/A" +"bundlemaker";"bundlemaker";"WIRE_BUNDLEMAKER";"N/A";3;"digital_bit";"digital_3bits" + + +# accept: which wiretype (defined elsewhere) the wires acceps. Use comma to separate multiple. N/A for electronic components (aka "not wires") +# inputcount: how many sides are input (outputcount is deduced from the inputcount). N/A for wires +# inputtype: which wiretype it accepts. N/A for wires +# outputtype: which wiretype it emits. N/A for wires diff --git a/assets/mods/basegame/items/itemid.csv b/assets/mods/basegame/items/itemid.csv index 85febde4f..858c25056 100644 --- a/assets/mods/basegame/items/itemid.csv +++ b/assets/mods/basegame/items/itemid.csv @@ -1,7 +1,7 @@ "id";"classname" -"135168";"net.torvald.terrarum.modulebasegame.gameitems.PickaxeCopper" -"135169";"net.torvald.terrarum.modulebasegame.gameitems.PickaxeIron" -"135170";"net.torvald.terrarum.modulebasegame.gameitems.PickaxeSteel" -"135171";"net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire" -"135172";"net.torvald.terrarum.modulebasegame.gameitems.TikiTorchTester" -"135173";"net.torvald.terrarum.modulebasegame.gameitems.ItemCraftingTable" +"1";"net.torvald.terrarum.modulebasegame.gameitems.PickaxeCopper" +"2";"net.torvald.terrarum.modulebasegame.gameitems.PickaxeIron" +"3";"net.torvald.terrarum.modulebasegame.gameitems.PickaxeSteel" +"4";"net.torvald.terrarum.modulebasegame.gameitems.WirePieceSignalWire" +"5";"net.torvald.terrarum.modulebasegame.gameitems.TikiTorchTester" +"6";"net.torvald.terrarum.modulebasegame.gameitems.ItemCraftingTable" diff --git a/assets/tiling.frag b/assets/tiling.frag index b71bba952..b1a01fd64 100644 --- a/assets/tiling.frag +++ b/assets/tiling.frag @@ -76,7 +76,7 @@ void main() { int tile = getTileFromColor(tileFromMap); int breakage = getBreakageFromColor(tileFromMap); ivec2 tileXY = getTileXY(tile); - ivec2 breakageXY = getTileXY(breakage + 5); // +5 is hard-coded constant that depends on the atlas + ivec2 breakageXY = getTileXY(breakage + 5); // +5 is hard-coded constant that depends on the contents of the atlas // calculate the UV coord value for texture sampling // diff --git a/src/net/torvald/terrarum/AppLoader.java b/src/net/torvald/terrarum/AppLoader.java index 701b59491..fedda7d2f 100644 --- a/src/net/torvald/terrarum/AppLoader.java +++ b/src/net/torvald/terrarum/AppLoader.java @@ -33,6 +33,7 @@ import net.torvald.terrarum.modulebasegame.TerrarumIngame; import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory; import net.torvald.terrarum.utils.JsonFetcher; import net.torvald.terrarum.utils.JsonWriter; +import net.torvald.terrarum.worlddrawer.CreateTileAtlas; import net.torvald.terrarumsansbitmap.gdx.GameFontBase; import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack; import net.torvald.util.ArrayListMap; @@ -494,6 +495,10 @@ public class AppLoader implements ApplicationListener { // make loading list CommonResourcePool.INSTANCE.loadAll(); + + // create tile atlas + printdbg(this, "Making terrain textures..."); + CreateTileAtlas.INSTANCE.invoke(false); } @Override @@ -1123,6 +1128,21 @@ public class AppLoader implements ApplicationListener { return ((float[]) cfg); } + public static String[] getConfigStringArray(String key) { + Object cfg = getConfigMaster(key); + if (cfg instanceof JsonArray) { + JsonArray jsonArray = ((JsonArray) cfg).getAsJsonArray(); + //return IntArray(jsonArray.size(), { i -> jsonArray[i].asInt }) + String[] intArray = new String[jsonArray.size()]; + for (int i = 0; i < jsonArray.size(); i++) { + intArray[i] = jsonArray.get(i).getAsString(); + } + return intArray; + } + else + return ((String[]) cfg); + } + /** * Get config from config file. If the entry does not exist, get from defaults; if the entry is not in the default, NullPointerException will be thrown */ diff --git a/src/net/torvald/terrarum/DefaultConfig.kt b/src/net/torvald/terrarum/DefaultConfig.kt index 864acff0f..edf75b16d 100644 --- a/src/net/torvald/terrarum/DefaultConfig.kt +++ b/src/net/torvald/terrarum/DefaultConfig.kt @@ -111,7 +111,7 @@ object DefaultConfig { // settings regarding debugger val buildingMakerFavs = JsonArray() - intArrayOf( + arrayOf( Block.GLASS_CRUDE, Block.PLANK_NORMAL, Block.PLANK_BIRCH, @@ -120,9 +120,10 @@ object DefaultConfig { Block.STONE_TILE_WHITE, Block.TORCH, - Block.PLANK_NORMAL + BlockCodex.MAX_TERRAIN_TILES, - Block.PLANK_BIRCH + BlockCodex.MAX_TERRAIN_TILES, - Block.GLASS_CRUDE + BlockCodex.MAX_TERRAIN_TILES).forEach { + "wall@" + Block.PLANK_NORMAL, + "wall@" + Block.PLANK_BIRCH, + "wall@" + Block.GLASS_CRUDE + ).forEach { buildingMakerFavs.add(it) } jsonObject.add("buildingmakerfavs", buildingMakerFavs) diff --git a/src/net/torvald/terrarum/IngameInstance.kt b/src/net/torvald/terrarum/IngameInstance.kt index ace45b7e0..e1a19734d 100644 --- a/src/net/torvald/terrarum/IngameInstance.kt +++ b/src/net/torvald/terrarum/IngameInstance.kt @@ -5,6 +5,7 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.utils.Queue import net.torvald.terrarum.AppLoader.printdbg import net.torvald.terrarum.gameactors.Actor +import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid import net.torvald.terrarum.realestate.LandUtil @@ -141,17 +142,17 @@ open class IngameInstance(val batch: SpriteBatch) : Screen { * * Queueing schema is used to make sure things are synchronised. */ - open fun queueTerrainChangedEvent(old: Int, new: Int, position: Long) { + open fun queueTerrainChangedEvent(old: ItemID, new: ItemID, position: Long) { val (x, y) = LandUtil.resolveBlockAddr(world, position) - terrainChangeQueue.addFirst(BlockChangeQueueItem(old, new, x, y)) + terrainChangeQueue.addLast(BlockChangeQueueItem(old, new, x, y)) } /** * Wall version of terrainChanged() event */ - open fun queueWallChangedEvent(old: Int, new: Int, position: Long) { + open fun queueWallChangedEvent(old: ItemID, new: ItemID, position: Long) { val (x, y) = LandUtil.resolveBlockAddr(world, position) - wallChangeQueue.addFirst(BlockChangeQueueItem(old, new, x, y)) + wallChangeQueue.addLast(BlockChangeQueueItem(old, new, x, y)) } /** @@ -160,9 +161,9 @@ open class IngameInstance(val batch: SpriteBatch) : Screen { * @param old previous settings of conduits in bit set format. * @param new current settings of conduits in bit set format. */ - open fun queueWireChangedEvent(old: Int, new: Int, position: Long) { + open fun queueWireChangedEvent(old: ItemID, new: ItemID, position: Long) { val (x, y) = LandUtil.resolveBlockAddr(world, position) - wireChangeQueue.addFirst(BlockChangeQueueItem(old, new, x, y)) + wireChangeQueue.addLast(BlockChangeQueueItem(old, new, x, y)) } @@ -252,7 +253,7 @@ open class IngameInstance(val batch: SpriteBatch) : Screen { - data class BlockChangeQueueItem(val old: Int, val new: Int, val posX: Int, val posY: Int) + data class BlockChangeQueueItem(val old: ItemID, val new: ItemID, val posX: Int, val posY: Int) open fun sendNotification(messages: Array) {} open fun sendNotification(messages: List) {} diff --git a/src/net/torvald/terrarum/ModMgr.kt b/src/net/torvald/terrarum/ModMgr.kt index 49e7cc330..3782d65e2 100644 --- a/src/net/torvald/terrarum/ModMgr.kt +++ b/src/net/torvald/terrarum/ModMgr.kt @@ -178,16 +178,19 @@ object ModMgr { } /** Get a common file (literal file or directory) from all the installed mods. Files are guaranteed to exist. If a mod does not - * contain the file, the mod will be skipped. */ - fun getFilesFromEveryMod(path: String): List { + * contain the file, the mod will be skipped. + * + * @return List of pairs + */ + fun getFilesFromEveryMod(path: String): List> { val path = path.sanitisePath() val moduleNames = moduleInfo.keys.toList() - val filesList = ArrayList() + val filesList = ArrayList>() moduleNames.forEach { val file = File(getPath(it, path)) - if (file.exists()) filesList.add(file) + if (file.exists()) filesList.add(it to file) } return filesList.toList() @@ -196,16 +199,18 @@ object ModMgr { /** Get a common file (literal file or directory) from all the installed mods. Files are guaranteed to exist. If a mod does not * contain the file, the mod will be skipped. * - * Returning files are read-only. */ - fun getGdxFilesFromEveryMod(path: String): List { + * Returning files are read-only. + * @return List of pairs + */ + fun getGdxFilesFromEveryMod(path: String): List> { val path = path.sanitisePath() val moduleNames = moduleInfo.keys.toList() - val filesList = ArrayList() + val filesList = ArrayList>() moduleNames.forEach { val file = Gdx.files.internal(getPath(it, path)) - if (file.exists()) filesList.add(file) + if (file.exists()) filesList.add(it to file) } return filesList.toList() @@ -230,16 +235,17 @@ object ModMgr { @JvmStatic operator fun invoke(module: String) { val csv = CSVFetcher.readFromModule(module, itemPath + "itemid.csv") csv.forEach { - val className = it["classname"].toString() - val itemID = it["id"].toInt() + val className: String = it["classname"].toString() + val internalID: Int = it["id"].toInt() + val itemName: String = "item@$module:$internalID" - printdbg(this, "Reading item #$itemID with className $className") + printdbg(this, "Reading item ${itemName} <<- internal #$internalID with className $className") val loadedClass = Class.forName(className) val loadedClassConstructor = loadedClass.getConstructor(ItemID::class.java) - val loadedClassInstance = loadedClassConstructor.newInstance(itemID) + val loadedClassInstance = loadedClassConstructor.newInstance(itemName) - ItemCodex[itemID] = loadedClassInstance as GameItem + ItemCodex[itemName] = loadedClassInstance as GameItem } } } diff --git a/src/net/torvald/terrarum/ReferencingRanges.kt b/src/net/torvald/terrarum/ReferencingRanges.kt index 8d4382403..febd3d459 100644 --- a/src/net/torvald/terrarum/ReferencingRanges.kt +++ b/src/net/torvald/terrarum/ReferencingRanges.kt @@ -22,4 +22,6 @@ object ReferencingRanges { val VIRTUAL_TILES = -2 downTo -1048576 // index of -1 breaks things for some reason :( + val PREFIX_DYNAMICITEM = "dyn:" + val PREFIX_ACTORITEM = "actor:" } \ No newline at end of file diff --git a/src/net/torvald/terrarum/blockproperties/Block.kt b/src/net/torvald/terrarum/blockproperties/Block.kt index d36cc1f77..72d90b192 100644 --- a/src/net/torvald/terrarum/blockproperties/Block.kt +++ b/src/net/torvald/terrarum/blockproperties/Block.kt @@ -5,128 +5,128 @@ package net.torvald.terrarum.blockproperties */ object Block { - const val AIR = 0 // hard coded; this is the standard + const val AIR = "basegame:0" // hard coded; this is the standard - const val STONE = 16 - const val STONE_QUARRIED = 17 - const val STONE_TILE_WHITE = 18 - const val STONE_BRICKS = 19 + const val STONE = "basegame:16" + const val STONE_QUARRIED = "basegame:17" + const val STONE_TILE_WHITE = "basegame:18" + const val STONE_BRICKS = "basegame:19" - const val DIRT = 32 - const val GRASS = 33 - const val GRASSWALL = 34 + const val DIRT = "basegame:32" + const val GRASS = "basegame:33" + const val GRASSWALL = "basegame:34" - const val PLANK_NORMAL = 48 - const val PLANK_EBONY = 49 - const val PLANK_BIRCH = 50 - const val PLANK_BLOODROSE = 51 + const val PLANK_NORMAL = "basegame:48" + const val PLANK_EBONY = "basegame:49" + const val PLANK_BIRCH = "basegame:50" + const val PLANK_BLOODROSE = "basegame:51" - const val TRUNK_NORMAL = 64 - const val TRUNK_EBONY = 65 - const val TRUNK_BIRCH = 66 - const val TRUNK_BLOODROSE = 67 + const val TRUNK_NORMAL = "basegame:64" + const val TRUNK_EBONY = "basegame:65" + const val TRUNK_BIRCH = "basegame:66" + const val TRUNK_BLOODROSE = "basegame:67" - const val SAND = 80 - const val SAND_WHITE = 81 - const val SAND_RED = 82 - const val SAND_DESERT = 83 - const val SAND_BLACK = 84 - const val SAND_GREEN = 85 + const val SAND = "basegame:80" + const val SAND_WHITE = "basegame:81" + const val SAND_RED = "basegame:82" + const val SAND_DESERT = "basegame:83" + const val SAND_BLACK = "basegame:84" + const val SAND_GREEN = "basegame:85" - const val GRAVEL = 96 - const val GRAVEL_GREY = 97 + const val GRAVEL = "basegame:96" + const val GRAVEL_GREY = "basegame:97" - const val ORE_COPPER = 112 - const val ORE_IRON = 113 - const val ORE_GOLD = 114 - const val ORE_SILVER = 115 - const val ORE_ILMENITE = 116 - const val ORE_AURICHALCUM = 117 + const val ORE_COPPER = "basegame:112" + const val ORE_IRON = "basegame:113" + const val ORE_GOLD = "basegame:114" + const val ORE_SILVER = "basegame:115" + const val ORE_ILMENITE = "basegame:116" + const val ORE_AURICHALCUM = "basegame:117" - const val RAW_RUBY = 128 - const val RAW_EMERALD = 129 - const val RAW_SAPPHIRE = 130 - const val RAW_TOPAZ = 131 - const val RAW_DIAMOND = 132 - const val RAW_AMETHYST = 133 + const val RAW_RUBY = "basegame:128" + const val RAW_EMERALD = "basegame:129" + const val RAW_SAPPHIRE = "basegame:130" + const val RAW_TOPAZ = "basegame:131" + const val RAW_DIAMOND = "basegame:132" + const val RAW_AMETHYST = "basegame:133" - const val SNOW = 144 - const val ICE_FRAGILE = 145 - const val ICE_NATURAL = 146 - const val ICE_MAGICAL = 147 + const val SNOW = "basegame:144" + const val ICE_FRAGILE = "basegame:145" + const val ICE_NATURAL = "basegame:146" + const val ICE_MAGICAL = "basegame:147" - const val GLASS_CRUDE = 148 - const val GLASS_CLEAN = 149 + const val GLASS_CRUDE = "basegame:148" + const val GLASS_CLEAN = "basegame:149" - const val PLATFORM_STONE = 160 - const val PLATFORM_WOODEN = 161 - const val PLATFORM_EBONY = 162 - const val PLATFORM_BIRCH = 163 - const val PLATFORM_BLOODROSE = 164 + const val PLATFORM_STONE = "basegame:160" + const val PLATFORM_WOODEN = "basegame:161" + const val PLATFORM_EBONY = "basegame:162" + const val PLATFORM_BIRCH = "basegame:163" + const val PLATFORM_BLOODROSE = "basegame:164" - const val TORCH = 176 - const val TORCH_FROST = 177 + const val TORCH = "basegame:176" + const val TORCH_FROST = "basegame:177" - const val TORCH_OFF = 192 - const val TORCH_FROST_OFF = 193 + const val TORCH_OFF = "basegame:192" + const val TORCH_FROST_OFF = "basegame:193" - const val ILLUMINATOR_WHITE = 208 - const val ILLUMINATOR_YELLOW = 209 - const val ILLUMINATOR_ORANGE = 210 - const val ILLUMINATOR_RED = 211 - const val ILLUMINATOR_FUCHSIA = 212 - const val ILLUMINATOR_PURPLE = 213 - const val ILLUMINATOR_BLUE = 214 - const val ILLUMINATOR_CYAN = 215 - const val ILLUMINATOR_GREEN = 216 - const val ILLUMINATOR_GREEN_DARK = 217 - const val ILLUMINATOR_BROWN = 218 - const val ILLUMINATOR_TAN = 219 - const val ILLUMINATOR_GREY_LIGHT = 220 - const val ILLUMINATOR_GREY_MED = 221 - const val ILLUMINATOR_GREY_DARK = 222 - const val ILLUMINATOR_BLACK = 223 + const val ILLUMINATOR_WHITE = "basegame:208" + const val ILLUMINATOR_YELLOW = "basegame:209" + const val ILLUMINATOR_ORANGE = "basegame:210" + const val ILLUMINATOR_RED = "basegame:211" + const val ILLUMINATOR_FUCHSIA = "basegame:212" + const val ILLUMINATOR_PURPLE = "basegame:213" + const val ILLUMINATOR_BLUE = "basegame:214" + const val ILLUMINATOR_CYAN = "basegame:215" + const val ILLUMINATOR_GREEN = "basegame:216" + const val ILLUMINATOR_GREEN_DARK = "basegame:217" + const val ILLUMINATOR_BROWN = "basegame:218" + const val ILLUMINATOR_TAN = "basegame:219" + const val ILLUMINATOR_GREY_LIGHT = "basegame:220" + const val ILLUMINATOR_GREY_MED = "basegame:221" + const val ILLUMINATOR_GREY_DARK = "basegame:222" + const val ILLUMINATOR_BLACK = "basegame:223" - const val ILLUMINATOR_WHITE_OFF = 224 - const val ILLUMINATOR_YELLOW_OFF = 225 - const val ILLUMINATOR_ORANGE_OFF = 226 - const val ILLUMINATOR_RED_OFF = 227 - const val ILLUMINATOR_FUCHSIA_OFF = 228 - const val ILLUMINATOR_PURPLE_OFF = 229 - const val ILLUMINATOR_BLUE_OFF = 230 - const val ILLUMINATOR_CYAN_OFF = 231 - const val ILLUMINATOR_GREEN_OFF = 232 - const val ILLUMINATOR_GREEN_DARK_OFF = 233 - const val ILLUMINATOR_BROWN_OFF = 234 - const val ILLUMINATOR_TAN_OFF = 235 - const val ILLUMINATOR_GREY_LIGHT_OFF = 236 - const val ILLUMINATOR_GREY_MED_OFF = 237 - const val ILLUMINATOR_GREY_DARK_OFF = 238 - const val ILLUMINATOR_BLACK_OFF = 239 + const val ILLUMINATOR_WHITE_OFF = "basegame:224" + const val ILLUMINATOR_YELLOW_OFF = "basegame:225" + const val ILLUMINATOR_ORANGE_OFF = "basegame:226" + const val ILLUMINATOR_RED_OFF = "basegame:227" + const val ILLUMINATOR_FUCHSIA_OFF = "basegame:228" + const val ILLUMINATOR_PURPLE_OFF = "basegame:229" + const val ILLUMINATOR_BLUE_OFF = "basegame:230" + const val ILLUMINATOR_CYAN_OFF = "basegame:231" + const val ILLUMINATOR_GREEN_OFF = "basegame:232" + const val ILLUMINATOR_GREEN_DARK_OFF = "basegame:233" + const val ILLUMINATOR_BROWN_OFF = "basegame:234" + const val ILLUMINATOR_TAN_OFF = "basegame:235" + const val ILLUMINATOR_GREY_LIGHT_OFF = "basegame:236" + const val ILLUMINATOR_GREY_MED_OFF = "basegame:237" + const val ILLUMINATOR_GREY_DARK_OFF = "basegame:238" + const val ILLUMINATOR_BLACK_OFF = "basegame:239" - const val SANDSTONE = 240 - const val SANDSTONE_WHITE = 241 - const val SANDSTONE_RED = 242 - const val SANDSTONE_DESERT = 243 - const val SANDSTONE_BLACK = 244 - const val SANDSTONE_GREEN = 245 + const val SANDSTONE = "basegame:240" + const val SANDSTONE_WHITE = "basegame:241" + const val SANDSTONE_RED = "basegame:242" + const val SANDSTONE_DESERT = "basegame:243" + const val SANDSTONE_BLACK = "basegame:244" + const val SANDSTONE_GREEN = "basegame:245" - const val LANTERN = 256 - const val SUNSTONE = 257 - const val DAYLIGHT_CAPACITOR = 258 + const val LANTERN = "basegame:256" + const val SUNSTONE = "basegame:257" + const val DAYLIGHT_CAPACITOR = "basegame:258" - const val ACTORBLOCK_NO_COLLISION = 4091 - const val ACTORBLOCK_FULL_COLLISION = 4092 - const val ACTORBLOCK_ALLOW_MOVE_DOWN = 4093 - const val ACTORBLOCK_NO_PASS_RIGHT = 4094 - const val ACTORBLOCK_NO_PASS_LEFT = 4095 + const val ACTORBLOCK_NO_COLLISION = "basegame:4091" + const val ACTORBLOCK_FULL_COLLISION = "basegame:4092" + const val ACTORBLOCK_ALLOW_MOVE_DOWN = "basegame:4093" + const val ACTORBLOCK_NO_PASS_RIGHT = "basegame:4094" + const val ACTORBLOCK_NO_PASS_LEFT = "basegame:4095" - const val LAVA = 4094 - const val WATER = 4095 + const val LAVA = "basegame:4094" + const val WATER = "basegame:4095" - const val NULL = -1 + const val NULL = "basegame:-1" val actorblocks = listOf( ACTORBLOCK_NO_COLLISION, diff --git a/src/net/torvald/terrarum/blockproperties/BlockCodex.kt b/src/net/torvald/terrarum/blockproperties/BlockCodex.kt index c3b34f3d5..cc3568c7b 100644 --- a/src/net/torvald/terrarum/blockproperties/BlockCodex.kt +++ b/src/net/torvald/terrarum/blockproperties/BlockCodex.kt @@ -5,6 +5,7 @@ import net.torvald.terrarum.AppLoader import net.torvald.terrarum.AppLoader.printdbg import net.torvald.terrarum.AppLoader.printmsg import net.torvald.terrarum.ReferencingRanges +import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.gameworld.FluidType import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.utils.CSVFetcher @@ -18,12 +19,12 @@ import java.io.IOException */ object BlockCodex { - private var blockProps = HashMap() + private var blockProps = HashMap() - val dynamicLights = SortedArrayList() // does not include virtual ones + val dynamicLights = SortedArrayList() // does not include virtual ones /** 65536 */ - val MAX_TERRAIN_TILES = GameWorld.TILES_SUPPORTED + //val MAX_TERRAIN_TILES = GameWorld.TILES_SUPPORTED private val nullProp = BlockProp() @@ -32,12 +33,17 @@ object BlockCodex { // fake props for "randomised" dynamic lights const val DYNAMIC_RANDOM_CASES = 64 - var virtualPropsCount = 0 - private set - /** always points to the HIGHEST prop ID. */ - val dynamicToVirtualPropMapping = ArrayList>() - /** for random access dont iterate over this */ - val dynamicToVirtualMap = hashMapOf() + private var virtualTileCursor = 1 + + /** + * One-to-Many + */ + val tileToVirtual = HashMap>() + + /** + * Many-to-One + */ + val virtualToTile = HashMap() /** * Later entry (possible from other modules) will replace older ones @@ -56,27 +62,28 @@ object BlockCodex { setProp(blockProps[intVal(it, "id")], it) }*/ - val id = intVal(it, "id") - setProp(id, it) + setProp(module, intVal(it, "id"), it) + val tileId = "$module:${intVal(it, "id")}" // register tiles with dynamic light - if ((blockProps[id]?.dynamicLuminosityFunction ?: 0) != 0) { - dynamicLights.add(id) + if ((blockProps[tileId]?.dynamicLuminosityFunction ?: 0) != 0) { + dynamicLights.add(tileId) // add virtual props for dynamic lights - val virtualIDMax = ReferencingRanges.VIRTUAL_TILES.first - virtualPropsCount - dynamicToVirtualPropMapping.add(id to virtualIDMax) - dynamicToVirtualMap[id] = virtualIDMax - repeat(DYNAMIC_RANDOM_CASES) { i -> - setProp(virtualIDMax - i, it) - printdbg(this, "Block ID $id -> Virtual ID ${virtualIDMax - i}, baseLum: ${blockProps[virtualIDMax - i]?.baseLumCol}") + val virtualChunk = ArrayList() + repeat(DYNAMIC_RANDOM_CASES) { _ -> + val virtualID = "virt:$virtualTileCursor" - virtualPropsCount += 1 + virtualToTile[virtualID] = tileId + virtualChunk.add(virtualID) + + setProp("virt", virtualTileCursor, it) + + printdbg(this, "Block ID $tileId -> Virtual ID $virtualID, baseLum: ${blockProps[virtualID]?.baseLumCol}") + virtualTileCursor += 1 } + tileToVirtual[tileId] = virtualChunk.sorted().toList() } - - if (id > highestNumber) - highestNumber = id } } catch (e: IOException) { @@ -84,6 +91,8 @@ object BlockCodex { } } + fun getAll() = blockProps.values + /*fun get(index: Int): BlockProp { try { return blockProps[index] @@ -97,7 +106,7 @@ object BlockCodex { } }*/ - operator fun get(rawIndex: Int?): BlockProp { + /*operator fun get(rawIndex: Int?): BlockProp { if (rawIndex == null || rawIndex == Block.NULL) { return nullProp } @@ -108,31 +117,45 @@ object BlockCodex { catch (e: NullPointerException) { throw NullPointerException("Blockprop with raw id $rawIndex does not exist.") } - } - - operator fun get(fluidType: FluidType?): BlockProp { - if (fluidType == null || fluidType.value == 0) { - return blockProps[Block.AIR]!! + }*/ + operator fun get(blockID: ItemID?): BlockProp { + if (blockID == null || blockID == "basegame:"+Block.NULL) { + return nullProp } try { - return blockProps[fluidType.abs() + GameWorld.TILES_SUPPORTED - 1]!! + return blockProps[blockID]!! } catch (e: NullPointerException) { - throw NullPointerException("Blockprop with raw id $fluidType does not exist.") + throw NullPointerException("Blockprop with id $blockID does not exist.") } } - fun getOrNull(rawIndex: Int?): BlockProp? {// - return blockProps[rawIndex] + operator fun get(fluidType: FluidType?): BlockProp { + // TODO fluid from other mods + + if (fluidType == null || fluidType.value == 0) { + return blockProps["basegame:"+Block.AIR]!! + } + + try { + return blockProps["basegame:${fluidType.abs() + GameWorld.TILES_SUPPORTED - 1}"]!! + } + catch (e: NullPointerException) { + throw NullPointerException("Blockprop with id $fluidType does not exist.") + } } - private fun setProp(key: Int, record: CSVRecord) { + fun getOrNull(blockID: ItemID?): BlockProp? {// + return blockProps[blockID] + } + + private fun setProp(modname: String, key: Int, record: CSVRecord) { val prop = BlockProp() prop.nameKey = record.get("name") - prop.id = if (key == -1) 0 else intVal(record, "id") - prop.drop = intVal(record, "drop") + prop.id = "$modname:$key" + prop.drop = "$modname:${intVal(record, "drop")}" prop.shadeColR = floatVal(record, "shdr") prop.shadeColG = floatVal(record, "shdg") @@ -163,9 +186,9 @@ object BlockCodex { prop.dynamicLuminosityFunction = intVal(record, "dlfn") - blockProps[key] = prop + blockProps[prop.id] = prop - printmsg(this, "${intVal(record, "id")}\t" + prop.nameKey) + printmsg(this, "Setting prop ${prop.id} ->>\t${prop.nameKey}\tsolid:${prop.isSolid}") } } diff --git a/src/net/torvald/terrarum/blockproperties/BlockProp.kt b/src/net/torvald/terrarum/blockproperties/BlockProp.kt index 4b2de07f0..9f94bc9ff 100644 --- a/src/net/torvald/terrarum/blockproperties/BlockProp.kt +++ b/src/net/torvald/terrarum/blockproperties/BlockProp.kt @@ -2,6 +2,7 @@ package net.torvald.terrarum.blockproperties import net.torvald.gdx.graphics.Cvec import net.torvald.random.XXHash32 +import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarum.serialise.toLittle @@ -10,7 +11,7 @@ import net.torvald.terrarum.serialise.toLittle */ class BlockProp { - var id: Int = 0 + var id: ItemID = "" var nameKey: String = "" @@ -62,14 +63,14 @@ class BlockProp { baseLumCol } else { val offset = XXHash32.hash(((x and 0xFFFF).shl(16) or (y and 0xFFFF)).toLittle(), 10000).fmod(BlockCodex.DYNAMIC_RANDOM_CASES) - BlockCodex[BlockCodex.dynamicToVirtualMap[id]!! - offset]._lumCol + BlockCodex[BlockCodex.tileToVirtual[id]!![offset]]._lumCol } fun getLumCol(x: Int, y: Int, channel: Int): Float = if (dynamicLuminosityFunction == 0) { baseLumCol.getElem(channel) } else { val offset = XXHash32.hash(((x and 0xFFFF).shl(16) or (y and 0xFFFF)).toLittle(), 10000).fmod(BlockCodex.DYNAMIC_RANDOM_CASES) - BlockCodex[BlockCodex.dynamicToVirtualMap[id]!! - offset]._lumCol.getElem(channel) + BlockCodex[BlockCodex.tileToVirtual[id]!![offset]]._lumCol.getElem(channel) } /** @@ -80,7 +81,7 @@ class BlockProp { //fun getLum(channel: Int) = lumCol.getElem(channel) - var drop: Int = 0 + var drop: ItemID = "" var maxSupport: Int = -1 // couldn't use NULL at all... diff --git a/src/net/torvald/terrarum/blockproperties/BlockPropUtil.kt b/src/net/torvald/terrarum/blockproperties/BlockPropUtil.kt index ae6ec8a38..c3330baa7 100644 --- a/src/net/torvald/terrarum/blockproperties/BlockPropUtil.kt +++ b/src/net/torvald/terrarum/blockproperties/BlockPropUtil.kt @@ -71,36 +71,34 @@ object BlockPropUtil { catch (skip: NullPointerException) {} }*/ // update randomised virtual props instead - for (keyMax in BlockCodex.dynamicToVirtualPropMapping) { - repeat(BlockCodex.DYNAMIC_RANDOM_CASES) { - val prop = BlockCodex[keyMax.second - it] - val domain = when (prop.dynamicLuminosityFunction) { - 1 -> flickerFuncDomain - 4 -> breathCycleDuration - 5 -> pulsateCycleDuration - else -> 0f - } - - // FPS-time compensation - if (Gdx.graphics.framesPerSecond > 0) { - prop.rngBase0 += Gdx.graphics.rawDeltaTime - } - - // reset timer - if (prop.rngBase0 > domain) { - prop.rngBase0 -= domain - - // flicker related - prop.rngBase1 = prop.rngBase2 - prop.rngBase2 = getNewRandom() - } - - prop._lumCol.set(getDynamicLumFunc(prop)) - //prop.lumColR = prop.lumCol.r - //prop.lumColG = prop.lumCol.g - //prop.lumColB = prop.lumCol.b - //prop.lumColA = prop.lumCol.a + for (key in BlockCodex.tileToVirtual.values.flatten()) { + val prop = BlockCodex[key] + val domain = when (prop.dynamicLuminosityFunction) { + 1 -> flickerFuncDomain + 4 -> breathCycleDuration + 5 -> pulsateCycleDuration + else -> 0f } + + // FPS-time compensation + if (Gdx.graphics.framesPerSecond > 0) { + prop.rngBase0 += Gdx.graphics.rawDeltaTime + } + + // reset timer + if (prop.rngBase0 > domain) { + prop.rngBase0 -= domain + + // flicker related + prop.rngBase1 = prop.rngBase2 + prop.rngBase2 = getNewRandom() + } + + prop._lumCol.set(getDynamicLumFunc(prop)) + //prop.lumColR = prop.lumCol.r + //prop.lumColG = prop.lumCol.g + //prop.lumColB = prop.lumCol.b + //prop.lumColA = prop.lumCol.a } } diff --git a/src/net/torvald/terrarum/blockstats/BlockStats.kt b/src/net/torvald/terrarum/blockstats/BlockStats.kt index fea0e1fcf..0702ad760 100644 --- a/src/net/torvald/terrarum/blockstats/BlockStats.kt +++ b/src/net/torvald/terrarum/blockstats/BlockStats.kt @@ -3,6 +3,7 @@ package net.torvald.terrarum.blockstats import com.jme3.math.FastMath import net.torvald.terrarum.AppLoader import net.torvald.terrarum.Terrarum +import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.worlddrawer.BlocksDrawer @@ -14,7 +15,7 @@ import java.util.* */ object BlockStats { - private val tilestat = ShortArray(GameWorld.TILES_SUPPORTED) + private val tilestat = HashMap() private val TSIZE = CreateTileAtlas.TILE_SIZE @@ -22,7 +23,7 @@ object BlockStats { * Update tile stats from tiles on screen */ fun update() { - Arrays.fill(tilestat, 0.toShort()) + tilestat.clear() // Get stats on no-zoomed screen area. In other words, will behave as if screen zoom were 1.0 // no matter how the screen is zoomed. @@ -47,29 +48,14 @@ object BlockStats { for (x in for_x_start..for_x_end - 1) { val tileWall = map.getTileFromWall(x, y) val tileTerrain = map.getTileFromTerrain(x, y) - ++tilestat[tileWall ?: 0] - ++tilestat[tileTerrain ?: 0] + tilestat[tileWall] = 1 + (tilestat[tileWall] ?: 0) + tilestat[tileTerrain] = 1 + (tilestat[tileTerrain] ?: 0) } } } - fun getCount(vararg tile: Byte): Int { - var sum = 0 - for (i in tile.indices) { - val newArgs = java.lang.Byte.toUnsignedInt(tile[i]) - sum += java.lang.Short.toUnsignedInt(tilestat[newArgs]) - } - - return sum + fun getCount(vararg tiles: ItemID): Int { + return tiles.fold(0) { acc, key -> acc + (tilestat[key] ?: 0) } } - fun getCount(vararg tile: Int): Int { - var sum = 0 - for (i in tile.indices) { - sum += java.lang.Short.toUnsignedInt(tilestat[tile[i]]) - } - return sum - } - - } diff --git a/src/net/torvald/terrarum/blockstats/MinimapComposer.kt b/src/net/torvald/terrarum/blockstats/MinimapComposer.kt index 247c6677d..a344ffdc1 100644 --- a/src/net/torvald/terrarum/blockstats/MinimapComposer.kt +++ b/src/net/torvald/terrarum/blockstats/MinimapComposer.kt @@ -134,10 +134,10 @@ object MinimapComposer : Disposable { for (y in topLeftY until topLeftY + LIVETILE_SIZE) { for (x in if (tileSlotIndexY >= TILES_IN_X / 2) (topLeftX + LIVETILE_SIZE - 1) downTo topLeftX else topLeftX until topLeftX + LIVETILE_SIZE) { - val tileTerr = world.getTileFromTerrain(x, y) ?: throw Error("OoB: $x, $y") - val wallTerr = world.getTileFromWall(x, y) ?: Block.AIR - val colTerr = CreateTileAtlas.terrainTileColourMap.get(tileTerr % 16, tileTerr / 16) - val colWall = CreateTileAtlas.terrainTileColourMap.get(wallTerr % 16, wallTerr / 16).mul(BlocksDrawer.wallOverlayColour) + val tileTerr = world.getTileFromTerrain(x, y) + val wallTerr = world.getTileFromWall(x, y) + val colTerr = CreateTileAtlas.terrainTileColourMap.get(tileTerr)!!.toGdxColor() + val colWall = CreateTileAtlas.terrainTileColourMap.get(wallTerr)!!.toGdxColor().mul(CreateTileAtlas.wallOverlayColour) val outCol = if (colTerr.a > 0.1f) colTerr else colWall diff --git a/src/net/torvald/terrarum/gameactors/ActorWithBody.kt b/src/net/torvald/terrarum/gameactors/ActorWithBody.kt index 0103ea7e6..3c10f9e5a 100644 --- a/src/net/torvald/terrarum/gameactors/ActorWithBody.kt +++ b/src/net/torvald/terrarum/gameactors/ActorWithBody.kt @@ -10,6 +10,7 @@ import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.blockproperties.BlockProp import net.torvald.terrarum.gamecontroller.KeyToggler +import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.gameworld.BlockAddress import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid @@ -1231,7 +1232,7 @@ open class ActorWithBody(renderOrder: RenderOrder, val physProp: PhysProperties) * * Very straightforward for the actual solid tiles, not so much for the platforms */ - private fun shouldICollideWithThis(tile: Int) = + private fun shouldICollideWithThis(tile: ItemID) = // regular solid block (BlockCodex[tile].isSolid) @@ -1240,7 +1241,7 @@ open class ActorWithBody(renderOrder: RenderOrder, val physProp: PhysProperties) * * Just like "shouldICollideWithThis" but it's intended to work with feet tiles */ - private fun shouldICollideWithThisFeet(tile: Int) = + private fun shouldICollideWithThisFeet(tile: ItemID) = // regular solid block (BlockCodex[tile].isSolid) || // platforms, moving downward AND not "going down" @@ -1295,7 +1296,7 @@ open class ActorWithBody(renderOrder: RenderOrder, val physProp: PhysProperties) return contactAreaCounter } - private fun getTileFriction(tile: Int) = + private fun getTileFriction(tile: ItemID) = if (physProp.immobileBody && tile == Block.AIR) BlockCodex[Block.AIR].friction.frictionToMult().div(500) .times(if (!grounded) elasticity else 1.0) @@ -1705,11 +1706,11 @@ open class ActorWithBody(renderOrder: RenderOrder, val physProp: PhysProperties) } - private fun forEachOccupyingTileNum(consumer: (Int?) -> Unit) { + private fun forEachOccupyingTileNum(consumer: (ItemID?) -> Unit) { if (world == null) return - val tiles = ArrayList() + val tiles = ArrayList() for (y in hIntTilewiseHitbox.startY.toInt()..hIntTilewiseHitbox.endY.toInt()) { for (x in hIntTilewiseHitbox.startX.toInt()..hIntTilewiseHitbox.endX.toInt()) { tiles.add(world!!.getTileFromTerrain(x, y)) @@ -1770,11 +1771,11 @@ open class ActorWithBody(renderOrder: RenderOrder, val physProp: PhysProperties) return tilePosList.forEach(consumer) } - private fun forEachFeetTileNum(consumer: (Int?) -> Unit) { + private fun forEachFeetTileNum(consumer: (ItemID?) -> Unit) { if (world == null) return - val tiles = ArrayList() + val tiles = ArrayList() // offset 1 pixel to the down so that friction would work val y = hitbox.endY.plus(1.0).div(TILE_SIZE).floorInt() diff --git a/src/net/torvald/terrarum/gamecontroller/IngameController.kt b/src/net/torvald/terrarum/gamecontroller/IngameController.kt index dcbc9d923..2fa7d8198 100644 --- a/src/net/torvald/terrarum/gamecontroller/IngameController.kt +++ b/src/net/torvald/terrarum/gamecontroller/IngameController.kt @@ -46,6 +46,8 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() { } } + private var worldPrimaryClickLatched = false + fun update(delta: Float) { /////////////////// @@ -61,13 +63,18 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() { // also, some UIs should NOT affect item usage (e.g. quickslot) and ingame's uiOpened property is doing // the very job. - if (Gdx.input.isButtonPressed(AppLoader.getConfigInt("config_mouseprimary"))) { + if (Gdx.input.isButtonPressed(AppLoader.getConfigInt("config_mouseprimary")) && !worldPrimaryClickLatched) { terrarumIngame.worldPrimaryClickStart(AppLoader.UPDATE_RATE) + worldPrimaryClickLatched = true } /*if Gdx.input.isButtonPressed(AppLoader.getConfigInt("config_mousesecondary")) { ingame.worldSecondaryClickStart(AppLoader.UPDATE_RATE) }*/ + if (!Gdx.input.isButtonPressed(AppLoader.getConfigInt("config_mouseprimary"))) { + worldPrimaryClickLatched = false + } + } diff --git a/src/net/torvald/terrarum/gameitem/GameItem.kt b/src/net/torvald/terrarum/gameitem/GameItem.kt index 5a6767d40..ac20a0431 100644 --- a/src/net/torvald/terrarum/gameitem/GameItem.kt +++ b/src/net/torvald/terrarum/gameitem/GameItem.kt @@ -4,14 +4,14 @@ import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.g2d.TextureRegion import net.torvald.random.HQRNG import net.torvald.terrarum.ItemValue +import net.torvald.terrarum.ReferencingRanges.PREFIX_DYNAMICITEM import net.torvald.terrarum.itemproperties.ItemCodex -import net.torvald.terrarum.itemproperties.ItemCodex.ITEM_DYNAMIC import net.torvald.terrarum.itemproperties.Material import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.modulebasegame.gameactors.ActorInventory import net.torvald.terrarum.modulebasegame.gameactors.Pocketed -typealias ItemID = Int +typealias ItemID = String /** * Instances of the GameItem (e.g. net.torvald.terrarum.modulebasegame.gameitems.PickaxeCopper) are preferably referenced @@ -40,7 +40,7 @@ abstract class GameItem(val originalID: ItemID) : Comparable, Cloneabl abstract val originalName: String - var newName: String = "I AM VITTUN PLACEHOLDER" + var newName: String = "I AM VITUN PLACEHOLDER" private set var name: String @@ -208,7 +208,7 @@ abstract class GameItem(val originalID: ItemID) : Comparable, Cloneabl } override fun hashCode(): Int { - return dynamicID + return dynamicID.hashCode() } override fun equals(other: Any?): Boolean { @@ -222,7 +222,7 @@ abstract class GameItem(val originalID: ItemID) : Comparable, Cloneabl nameColour = Color.WHITE } - override fun compareTo(other: GameItem): Int = (this.dynamicID - other.dynamicID).sign() + override fun compareTo(other: GameItem): Int = (this.dynamicID.substring(4).toInt() - other.dynamicID.substring(4).toInt()).sign() fun Int.sign(): Int = if (this > 0) 1 else if (this < 0) -1 else 0 @@ -295,7 +295,7 @@ abstract class GameItem(val originalID: ItemID) : Comparable, Cloneabl fun generateUniqueDynamicID(inventory: ActorInventory): GameItem { - dynamicID = Companion.generateUniqueDynamicID(inventory) + dynamicID = "$PREFIX_DYNAMICITEM${Companion.generateUniqueDynamicID(inventory)}" ItemCodex.registerNewDynamicItem(dynamicID, this) return this } @@ -307,8 +307,8 @@ abstract class GameItem(val originalID: ItemID) : Comparable, Cloneabl fun generateUniqueDynamicID(inventory: ActorInventory): Int { var ret: Int do { - ret = ITEM_DYNAMIC.pickRandom() - } while (inventory.contains(ret)) + ret = (1..2147483647).pickRandom() + } while (inventory.contains("$PREFIX_DYNAMICITEM$ret")) return ret } diff --git a/src/net/torvald/terrarum/gameworld/GameWorld.kt b/src/net/torvald/terrarum/gameworld/GameWorld.kt index 493465fe2..55fb376c2 100644 --- a/src/net/torvald/terrarum/gameworld/GameWorld.kt +++ b/src/net/torvald/terrarum/gameworld/GameWorld.kt @@ -9,10 +9,12 @@ import net.torvald.terrarum.Terrarum import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.blockproperties.Fluid +import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.modulebasegame.gameworld.WorldSimulator import net.torvald.terrarum.printStackTrace import net.torvald.terrarum.realestate.LandUtil import net.torvald.terrarum.serialise.ReadLayerDataZip +import net.torvald.terrarum.worlddrawer.CreateTileAtlas import net.torvald.util.SortedArrayList import org.dyn4j.geometry.Vector2 import kotlin.math.absoluteValue @@ -79,7 +81,7 @@ open class GameWorld : Disposable { /** * Used by the renderer. When wirings are updated, `wirings` and this properties must be synchronised. */ - private val wiringBlocks: HashMap + private val wiringBlocks: HashMap //public World physWorld = new World( new Vec2(0, -Terrarum.game.gravitationalAccel) ); //physics @@ -100,7 +102,14 @@ open class GameWorld : Disposable { open var TIME_T: Long = 0L open var dayLength: Int = 86400 + @TEMzPayload("TMaP", TEMzPayload.EXTERNAL_JSON) + val tileNumberToNameMap: HashMap + // does not go to the savefile + val tileNameToNumberMap: HashMap + /** + * Create new world + */ constructor(worldIndex: Int, width: Int, height: Int, creationTIME_T: Long, lastPlayTIME_T: Long, totalPlayTime: Int) { if (width <= 0 || height <= 0) throw IllegalArgumentException("Non-positive width/height: ($width, $height)") @@ -133,8 +142,24 @@ open class GameWorld : Disposable { creationTime = creationTIME_T lastPlayTime = lastPlayTIME_T this.totalPlayTime = totalPlayTime + + + tileNumberToNameMap = HashMap() + tileNameToNumberMap = HashMap() + CreateTileAtlas.tags.forEach { + printdbg(this, "tileNumber ${it.value.tileNumber} <-> tileName ${it.key}") + + tileNumberToNameMap[it.value.tileNumber] = it.key + tileNameToNumberMap[it.key] = it.value.tileNumber + } + + // AN EXCEPTIONAL TERM: tilenum 0 is always redirected to Air tile, even if the tilenum for actual Air tile is not zero + tileNumberToNameMap[0] = Block.AIR } + /** + * Load existing world + */ internal constructor(worldIndex: Int, layerData: ReadLayerDataZip.LayerData, creationTIME_T: Long, lastPlayTIME_T: Long, totalPlayTime: Int) { this.worldIndex = worldIndex @@ -160,6 +185,28 @@ open class GameWorld : Disposable { creationTime = creationTIME_T lastPlayTime = lastPlayTIME_T this.totalPlayTime = totalPlayTime + + // before the renaming, update the name maps + tileNumberToNameMap = HashMap() + tileNameToNumberMap = HashMap() + CreateTileAtlas.tags.forEach { + tileNumberToNameMap[it.value.tileNumber] = it.key + tileNameToNumberMap[it.key] = it.value.tileNumber + } + + // perform renaming of tile layers + val oldTileNumberToNameMap = layerData.tileNumberToNameMap + for (y in 0 until layerTerrain.height) { + for (x in 0 until layerTerrain.width) { + layerTerrain.unsafeSetTile(x, y, tileNameToNumberMap[oldTileNumberToNameMap[layerTerrain.unsafeGetTile(x, y)]]!!) + layerWall.unsafeSetTile(x, y, tileNameToNumberMap[oldTileNumberToNameMap[layerWall.unsafeGetTile(x, y)]]!!) + // TODO rename fluid map + // TODO rename wire map + } + } + + // AN EXCEPTIONAL TERM: tilenum 0 is always redirected to Air tile, even if the tilenum for actual Air tile is not zero + tileNumberToNameMap[0] = Block.AIR } /** @@ -172,12 +219,41 @@ open class GameWorld : Disposable { fun coerceXY(x: Int, y: Int) = (x fmod width) to (y.coerceIn(0, height - 1)) - fun getTileFromWall(rawX: Int, rawY: Int): Int { + /** + * @return ItemID, WITHOUT wall tag + */ + fun getTileFromWall(rawX: Int, rawY: Int): ItemID { + val (x, y) = coerceXY(rawX, rawY) + return tileNumberToNameMap[layerWall.unsafeGetTile(x, y)]!! + } + + /** + * @return ItemID + */ + fun getTileFromTerrain(rawX: Int, rawY: Int): ItemID { + val (x, y) = coerceXY(rawX, rawY) + + try { + return tileNumberToNameMap[layerTerrain.unsafeGetTile(x, y)]!! + } + catch (e: NullPointerException) { + System.err.println("NPE for tilenum ${layerTerrain.unsafeGetTile(x, y)}") + throw e + } + } + + /** + * @return Int + */ + fun getTileNumFromWall(rawX: Int, rawY: Int): Int { val (x, y) = coerceXY(rawX, rawY) return layerWall.unsafeGetTile(x, y) } - fun getTileFromTerrain(rawX: Int, rawY: Int): Int { + /** + * @return Int + */ + fun getTileNumFromTerrain(rawX: Int, rawY: Int): Int { val (x, y) = coerceXY(rawX, rawY) return layerTerrain.unsafeGetTile(x, y) } @@ -191,17 +267,18 @@ open class GameWorld : Disposable { * * * @param y * * - * @param tilenum Item id of the wall block. Less-than-4096-value is permitted. + * @param itemID Tile as in ItemID, with tag removed! */ - fun setTileWall(x: Int, y: Int, tilenum: Int) { + fun setTileWall(x: Int, y: Int, itemID: ItemID, bypassEvent: Boolean) { val (x, y) = coerceXY(x, y) - val tilenum = tilenum % TILES_SUPPORTED // does work without this, but to be safe... + val tilenum = tileNameToNumberMap[itemID]!! val oldWall = getTileFromWall(x, y) layerWall.unsafeSetTile(x, y, tilenum) wallDamages.remove(LandUtil.getBlockAddr(this, x, y)) - Terrarum.ingame?.queueWallChangedEvent(oldWall, tilenum, LandUtil.getBlockAddr(this, x, y)) + if (!bypassEvent) + Terrarum.ingame?.queueWallChangedEvent(oldWall, itemID, LandUtil.getBlockAddr(this, x, y)) } /** @@ -213,23 +290,25 @@ open class GameWorld : Disposable { * * * @param y * * - * @param tilenum Item id of the terrain block, <4096 + * @param itemID Tile as in ItemID, with tag removed! */ - fun setTileTerrain(x: Int, y: Int, tilenum: Int) { + fun setTileTerrain(x: Int, y: Int, itemID: ItemID, bypassEvent: Boolean) { val (x, y) = coerceXY(x, y) + val tilenum = tileNameToNumberMap[itemID]!! val oldTerrain = getTileFromTerrain(x, y) layerTerrain.unsafeSetTile(x, y, tilenum) val blockAddr = LandUtil.getBlockAddr(this, x, y) terrainDamages.remove(blockAddr) - if (BlockCodex[tilenum].isSolid) { + if (BlockCodex[itemID].isSolid) { fluidFills.remove(blockAddr) fluidTypes.remove(blockAddr) } // fluid tiles-item should be modified so that they will also place fluid onto their respective map - Terrarum.ingame?.queueTerrainChangedEvent(oldTerrain, tilenum, LandUtil.getBlockAddr(this, x, y)) + if (!bypassEvent) + Terrarum.ingame?.queueTerrainChangedEvent(oldTerrain, itemID, LandUtil.getBlockAddr(this, x, y)) } /*fun setTileWire(x: Int, y: Int, tile: Byte) { @@ -241,8 +320,9 @@ open class GameWorld : Disposable { Terrarum.ingame?.queueWireChangedEvent(oldWire, tile.toUint(), LandUtil.getBlockAddr(this, x, y)) }*/ - fun getWiringBlocks(x: Int, y: Int): Int { - return wiringBlocks.getOrDefault(LandUtil.getBlockAddr(this, x, y), 0) + fun getWiringBlocks(x: Int, y: Int): ItemID { + return Block.AIR // TODO + //return wiringBlocks.getOrDefault(LandUtil.getBlockAddr(this, x, y), Block.AIR) } fun getAllConduitsFrom(x: Int, y: Int): SortedArrayList? { @@ -258,7 +338,9 @@ open class GameWorld : Disposable { } fun addNewConduitTo(x: Int, y: Int, node: WiringNode) { - val blockAddr = LandUtil.getBlockAddr(this, x, y) + // TODO needs new conduit storage scheme + + /*val blockAddr = LandUtil.getBlockAddr(this, x, y) // check for existing type of conduit // if there's no duplicate... @@ -270,10 +352,10 @@ open class GameWorld : Disposable { } else { TODO("need overwriting policy for existing conduit node") - } + }*/ } - fun getTileFrom(mode: Int, x: Int, y: Int): Int? { + fun getTileFrom(mode: Int, x: Int, y: Int): ItemID { if (mode == TERRAIN) { return getTileFromTerrain(x, y) } @@ -287,8 +369,8 @@ open class GameWorld : Disposable { throw IllegalArgumentException("illegal mode input: " + mode.toString()) } - fun terrainIterator(): Iterator { - return object : Iterator { + fun terrainIterator(): Iterator { + return object : Iterator { private var iteratorCount = 0 @@ -296,7 +378,7 @@ open class GameWorld : Disposable { return iteratorCount < width * height } - override fun next(): Int { + override fun next(): ItemID { val y = iteratorCount / width val x = iteratorCount % width // advance counter @@ -308,15 +390,15 @@ open class GameWorld : Disposable { } } - fun wallIterator(): Iterator { - return object : Iterator { + fun wallIterator(): Iterator { + return object : Iterator { private var iteratorCount = 0 override fun hasNext(): Boolean = iteratorCount < width * height - override fun next(): Int { + override fun next(): ItemID { val y = iteratorCount / width val x = iteratorCount % width // advance counter @@ -351,7 +433,7 @@ open class GameWorld : Disposable { // remove tile from the world if (terrainDamages[addr] ?: 0f >= BlockCodex[getTileFromTerrain(x, y)].strength) { - setTileTerrain(x, y, 0) + setTileTerrain(x, y, Block.AIR, false) terrainDamages.remove(addr) return true } @@ -380,7 +462,7 @@ open class GameWorld : Disposable { // remove tile from the world if (wallDamages[addr]!! >= BlockCodex[getTileFromWall(x, y)].strength) { - setTileWall(x, y, 0) + setTileWall(x, y, Block.AIR, false) wallDamages.remove(addr) return true } diff --git a/src/net/torvald/terrarum/itemproperties/ItemCodex.kt b/src/net/torvald/terrarum/itemproperties/ItemCodex.kt index 1059cc548..26dc2b792 100644 --- a/src/net/torvald/terrarum/itemproperties/ItemCodex.kt +++ b/src/net/torvald/terrarum/itemproperties/ItemCodex.kt @@ -5,7 +5,11 @@ import net.torvald.terrarum.AppLoader import net.torvald.terrarum.AppLoader.printdbg import net.torvald.terrarum.CommonResourcePool import net.torvald.terrarum.ReferencingRanges +import net.torvald.terrarum.ReferencingRanges.PREFIX_ACTORITEM +import net.torvald.terrarum.ReferencingRanges.PREFIX_DYNAMICITEM import net.torvald.terrarum.Terrarum +import net.torvald.terrarum.blockproperties.BlockCodex +import net.torvald.terrarum.blockproperties.BlockProp import net.torvald.terrarum.blockproperties.Fluid import net.torvald.terrarum.gameitem.GameItem import net.torvald.terrarum.gameitem.ItemID @@ -13,6 +17,8 @@ import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.modulebasegame.gameactors.CanBeAnItem import net.torvald.terrarum.worlddrawer.BlocksDrawer +import net.torvald.terrarum.worlddrawer.CreateTileAtlas +import net.torvald.terrarum.worlddrawer.CreateTileAtlas.ITEM_ATLAS_TILES_X import java.util.* /** @@ -24,219 +30,19 @@ object ItemCodex { * * Will return corresponding Actor if ID >= ACTORID_MIN */ - val itemCodex = HashMap() + private val itemCodex = HashMap() val dynamicItemDescription = HashMap() val dynamicToStaticTable = HashMap() - val ITEM_TILES = ReferencingRanges.TILES - val ITEM_WALLS = ReferencingRanges.WALLS - val ITEM_WIRES = ReferencingRanges.WIRES - val ITEM_STATIC = ReferencingRanges.ITEMS_STATIC - val ITEM_DYNAMIC = ReferencingRanges.ITEMS_DYNAMIC val ACTORID_MIN = ReferencingRanges.ACTORS.first private val itemImagePlaceholder: TextureRegion get() = CommonResourcePool.getAsTextureRegion("itemplaceholder_24") // copper pickaxe - - // TODO: when generalised, there's no guarantee that blocks will be used as an item. Write customised item prop loader and init it on the Ingame - - init { - //val ingame = Terrarum.ingame!! as Ingame // WARNING you can't put this here, ExceptionInInitializerError - - - /*println("[ItemCodex] recording item ID ") - - // blocks.csvs are loaded by ModMgr beforehand - // block items (blocks and walls are the same thing basically) - for (i in ITEM_TILES + ITEM_WALLS) { - itemCodex[i] = object : GameItem() { - override val originalID = i - override var dynamicID = i - override val isUnique: Boolean = false - override var baseMass: Double = BlockCodex[i].density / 1000.0 - override var baseToolSize: Double? = null - override var equipPosition = EquipPosition.HAND_GRIP - override val originalName = BlockCodex[i % ITEM_WALLS.first].nameKey - override var stackable = true - override var inventoryCategory = if (i in ITEM_TILES) Category.BLOCK else Category.WALL - override var isDynamic = false - override val material = Material(0,0,0,0,0,0,0,0,0,0.0) - - init { - print("$originalID ") - } - - override fun startPrimaryUse(delta: Float): Boolean { - return false - // TODO base punch attack - } - - override fun startSecondaryUse(delta: Float): Boolean { - val mousePoint = Point2d(Terrarum.mouseTileX.toDouble(), Terrarum.mouseTileY.toDouble()) - - // check for collision with actors (BLOCK only) - if (this.inventoryCategory == Category.BLOCK) { - ingame.actorContainerActive.forEach { - if (it is ActorWBMovable && it.hIntTilewiseHitbox.intersects(mousePoint)) - return false - } - } - - // return false if the tile is already there - if (this.inventoryCategory == Category.BLOCK && - this.dynamicID == ingame.world.getTileFromTerrain(Terrarum.mouseTileX, Terrarum.mouseTileY) || - this.inventoryCategory == Category.WALL && - this.dynamicID - ITEM_WALLS.start == ingame.world.getTileFromWall(Terrarum.mouseTileX, Terrarum.mouseTileY) || - this.inventoryCategory == Category.WIRE && - this.dynamicID - ITEM_WIRES.start == ingame.world.getTileFromWire(Terrarum.mouseTileX, Terrarum.mouseTileY) - ) - return false - - // filter passed, do the job - // FIXME this is only useful for Player - if (i in ITEM_TILES) { - ingame.world.setTileTerrain( - Terrarum.mouseTileX, - Terrarum.mouseTileY, - i - ) - } - else { - ingame.world.setTileWall( - Terrarum.mouseTileX, - Terrarum.mouseTileY, - i - ) - } - - return true - } - } - }*/ - - // test copper pickaxe - /*itemCodex[ITEM_STATIC.first] = object : GameItem() { - override val originalID = ITEM_STATIC.first - override var dynamicID = originalID - override val isUnique = false - override val originalName = "" - override var baseMass = 10.0 - override var baseToolSize: Double? = 10.0 - override var stackable = true - override var maxDurability = 147//606 - override var durability = maxDurability.toFloat() - override var equipPosition = EquipPosition.HAND_GRIP - override var inventoryCategory = Category.TOOL - override val isDynamic = true - override val material = Material(0,0,0,0,0,0,0,0,1,0.0) - - init { - itemProperties[IVKey.ITEMTYPE] = IVKey.ItemType.PICK - name = "Stone pickaxe" - } - - override fun startPrimaryUse(delta: Float): Boolean { - val mousePoint = Point2d(Terrarum.mouseTileX.toDouble(), Terrarum.mouseTileY.toDouble()) - val actorvalue = ingame.actorNowPlaying.actorValue - - - using = true - - // linear search filter (check for intersection with tilewise mouse point and tilewise hitbox) - // return false if hitting actors - ingame.actorContainerActive.forEach { - if (it is ActorWBMovable && it.hIntTilewiseHitbox.intersects(mousePoint)) - return false - } - - // return false if there's no tile - if (Block.AIR == ingame.world.getTileFromTerrain(Terrarum.mouseTileX, Terrarum.mouseTileY)) - return false - - - // filter passed, do the job - val swingDmgToFrameDmg = delta.toDouble() / actorvalue.getAsDouble(AVKey.ACTION_INTERVAL)!! - - ingame.world.inflictTerrainDamage( - Terrarum.mouseTileX, - Terrarum.mouseTileY, - Calculate.pickaxePower(ingame.actorNowPlaying, material) * swingDmgToFrameDmg - ) - return true - } - - override fun endPrimaryUse(delta: Float): Boolean { - using = false - // reset action timer to zero - ingame.actorNowPlaying.actorValue[AVKey.__ACTION_TIMER] = 0.0 - return true - } - }*/ - - - // test water bucket - itemCodex[9000] = object : GameItem(9000) { - - override val isUnique: Boolean = true - override val originalName: String = "Infinite Water Bucket" - - override var baseMass: Double = 1000.0 - override var baseToolSize: Double? = null - - override var inventoryCategory: String = "tool" - override var stackable: Boolean = false - - override val isDynamic: Boolean = false - override val material: Material = Material() - - init { - equipPosition = EquipPosition.HAND_GRIP - } - - override fun startPrimaryUse(delta: Float): Boolean { - val ingame = Terrarum.ingame!! as TerrarumIngame // must be in here - ingame.world.setFluid(Terrarum.mouseTileX, Terrarum.mouseTileY, Fluid.WATER, 4f) - return true - } - } - - - // test lava bucket - itemCodex[9001] = object : GameItem(9001) { - - override val isUnique: Boolean = true - override val originalName: String = "Infinite Lava Bucket" - - override var baseMass: Double = 1000.0 - override var baseToolSize: Double? = null - - override var inventoryCategory: String = "tool" - override var stackable: Boolean = false - - override val isDynamic: Boolean = false - override val material: Material = Material() - - init { - equipPosition = EquipPosition.HAND_GRIP - } - - override fun startPrimaryUse(delta: Float): Boolean { - val ingame = Terrarum.ingame!! as TerrarumIngame // must be in here - ingame.world.setFluid(Terrarum.mouseTileX, Terrarum.mouseTileY, Fluid.LAVA, 4f) - return true - } - } - - - // read from save (if applicable) and fill dynamicItemDescription - - - - println() - } - - fun registerNewDynamicItem(dynamicID: Int, item: GameItem) { + /** + * @param: dynamicID string of "dyn:" + */ + fun registerNewDynamicItem(dynamicID: ItemID, item: GameItem) { if (AppLoader.IS_DEVELOPMENT_BUILD) { printdbg(this, "Registering new dynamic item $dynamicID (from ${item.originalID})") } @@ -251,18 +57,17 @@ object ItemCodex { operator fun get(code: ItemID?): GameItem? { if (code == null) return null - if (code <= ITEM_STATIC.endInclusive) // generic item - return itemCodex[code]!!.clone() // from CSV - else if (code <= ITEM_DYNAMIC.endInclusive) { + if (code.startsWith(PREFIX_DYNAMICITEM)) return dynamicItemDescription[code]!! - } - else { - val a = (Terrarum.ingame!! as TerrarumIngame).getActorByID(code) // actor item + else if (code.startsWith(PREFIX_ACTORITEM)) { + val a = (Terrarum.ingame!! as TerrarumIngame).getActorByID(code.substring(6).toInt()) // actor item if (a is CanBeAnItem) return a.itemData return null //throw IllegalArgumentException("Attempted to get item data of actor that cannot be an item. ($a)") } + else // generic item + return itemCodex[code]?.clone() // from CSV } fun dynamicToStaticID(dynamicID: ItemID) = dynamicToStaticTable[dynamicID]!! @@ -270,6 +75,10 @@ object ItemCodex { /** * Mainly used by GameItemLoader */ + fun set(modname: String, code: Int, item: GameItem) { + itemCodex["$modname:$code"] = item + } + operator fun set(code: ItemID, item: GameItem) { itemCodex[code] = item } @@ -280,31 +89,35 @@ object ItemCodex { return getItemImage(item.originalID) } - fun getItemImage(itemOriginalID: Int): TextureRegion { + fun getItemImage(itemID: ItemID?): TextureRegion? { + if (itemID == null) return null + // dynamic item - if (itemOriginalID in ITEM_DYNAMIC) { - return getItemImage(dynamicToStaticID(itemOriginalID)) + if (itemID.startsWith(PREFIX_DYNAMICITEM)) { + return getItemImage(dynamicToStaticID(itemID)) + } + // item + else if (itemID.startsWith("item@")) { + return itemCodex[itemID]?.itemImage + } + // TODO: wires + // wall + else if (itemID.startsWith("wall@")) { + val itemSheetNumber = CreateTileAtlas.tileIDtoItemSheetNumber(itemID.substring(5)) + return BlocksDrawer.tileItemWall.get( + itemSheetNumber % ITEM_ATLAS_TILES_X, + itemSheetNumber / ITEM_ATLAS_TILES_X + ) } // terrain - else if (itemOriginalID in ITEM_TILES) { + else { + val itemSheetNumber = CreateTileAtlas.tileIDtoItemSheetNumber(itemID) return BlocksDrawer.tileItemTerrain.get( - itemOriginalID % 16, - itemOriginalID / 16 + itemSheetNumber % ITEM_ATLAS_TILES_X, + itemSheetNumber / ITEM_ATLAS_TILES_X ) } - // wall - else if (itemOriginalID in ITEM_WALLS) { - return BlocksDrawer.tileItemWall.get( - (itemOriginalID.minus(ITEM_WALLS.first) % 16), - (itemOriginalID.minus(ITEM_WALLS.first) / 16) - ) - } - // wire - /*else if (itemOriginalID in ITEM_WIRES) { - return BlocksDrawer.tilesWire.get((itemOriginalID % 16) * 16, itemOriginalID / 16) - }*/ - else - return itemCodex[itemOriginalID]?.itemImage ?: itemImagePlaceholder + } fun hasItem(itemID: Int): Boolean = dynamicItemDescription.containsKey(itemID) diff --git a/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt b/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt index 47e59d2e9..8fad920b8 100644 --- a/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt +++ b/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt @@ -84,19 +84,19 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) { println("[BuildingMaker] Generating builder world...") for (y in 0 until gameWorld.height) { - gameWorld.setTileWall(0, y, Block.ILLUMINATOR_RED) - gameWorld.setTileWall(gameWorld.width - 1, y, Block.ILLUMINATOR_RED) - gameWorld.setTileTerrain(0, y, Block.ILLUMINATOR_RED_OFF) - gameWorld.setTileTerrain(gameWorld.width - 1, y, Block.ILLUMINATOR_RED_OFF) + gameWorld.setTileWall(0, y, Block.ILLUMINATOR_RED, true) + gameWorld.setTileWall(gameWorld.width - 1, y, Block.ILLUMINATOR_RED, true) + gameWorld.setTileTerrain(0, y, Block.ILLUMINATOR_RED_OFF, true) + gameWorld.setTileTerrain(gameWorld.width - 1, y, Block.ILLUMINATOR_RED_OFF, true) } for (y in 150 until gameWorld.height) { for (x in 1 until gameWorld.width - 1) { // wall layer - gameWorld.setTileWall(x, y, Block.DIRT) + gameWorld.setTileWall(x, y, Block.DIRT, true) // terrain layer - gameWorld.setTileTerrain(x, y, if (y == 150) Block.GRASS else Block.DIRT) + gameWorld.setTileTerrain(x, y, if (y == 150) Block.GRASS else Block.DIRT, true) } } @@ -424,22 +424,22 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) { when (currentPenMode) { // test paint terrain layer PENMODE_PENCIL -> { - if (palSelection < BlockCodex.MAX_TERRAIN_TILES) - world.setTileTerrain(x, y, palSelection) - else if (palSelection < 2 * BlockCodex.MAX_TERRAIN_TILES) - world.setTileWall(x, y, palSelection - BlockCodex.MAX_TERRAIN_TILES) + if (palSelection.startsWith("wall@")) + world.setTileWall(x, y, palSelection.substring(5), true) + else + world.setTileTerrain(x, y, palSelection, true) } PENMODE_PENCIL_ERASE -> { if (currentPenTarget and PENTARGET_WALL != 0) - world.setTileWall(x, y, Block.AIR) + world.setTileWall(x, y, Block.AIR, true) else - world.setTileTerrain(x, y, Block.AIR) + world.setTileTerrain(x, y, Block.AIR, true) } PENMODE_EYEDROPPER -> { uiPaletteSelector.fore = if (world.getTileFromTerrain(x, y) == Block.AIR) - world.getTileFromWall(x, y)!! + BlockCodex.MAX_TERRAIN_TILES + "wall@"+world.getTileFromWall(x, y) else - world.getTileFromTerrain(x, y)!! + world.getTileFromTerrain(x, y) } PENMODE_MARQUEE -> { addBlockMarker(x, y) @@ -455,7 +455,7 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) { return selection.last() - selection.first() } - private fun serialiseSelection(outfile: File) { + /*private fun serialiseSelection(outfile: File) { // save format: sparse list encoded in following binary format: /* Header: TEaT0bLD -- magic: Terrarum Attachment @@ -498,7 +498,7 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) { } fos.write(FILE_FOOTER) fos.close() - } + }*/ } class BuildingMakerController(val screen: BuildingMaker) : InputAdapter() { diff --git a/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt b/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt index 9d60f1159..9d67891dc 100644 --- a/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt +++ b/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt @@ -6,6 +6,7 @@ import net.torvald.terrarum.CommonResourcePool import net.torvald.terrarum.ModMgr import net.torvald.terrarum.ModuleEntryPoint import net.torvald.terrarum.blockproperties.BlockCodex +import net.torvald.terrarum.blockproperties.BlockProp import net.torvald.terrarum.gameitem.GameItem import net.torvald.terrarum.itemproperties.ItemCodex import net.torvald.terrarum.itemproperties.MaterialCodex @@ -52,35 +53,14 @@ class EntryPoint : ModuleEntryPoint() { // blocks.csvs are loaded by ModMgr beforehand // block items (blocks and walls are the same thing basically) - for (i in ItemCodex.ITEM_TILES + ItemCodex.ITEM_WALLS) { - val blockProp = BlockCodex.getOrNull(i % ItemCodex.ITEM_WALLS.first) + for (tile in BlockCodex.getAll()) { + ItemCodex[tile.id] = makeNewItemObj(tile, false) - if (blockProp != null) { - ItemCodex.itemCodex[i] = object : GameItem(i) { - override val isUnique: Boolean = false - override var baseMass: Double = blockProp.density / 1000.0 - override var baseToolSize: Double? = null - override val originalName = blockProp.nameKey - override var stackable = true - override var inventoryCategory = if (i in ItemCodex.ITEM_TILES) Category.BLOCK else Category.WALL - override var isDynamic = false - override val material = MaterialCodex.getOrDefault(blockProp.material) + if (IS_DEVELOPMENT_BUILD) print(tile.id+" ") - init { - equipPosition = EquipPosition.HAND_GRIP - - if (IS_DEVELOPMENT_BUILD) - print("$originalID ") - } - - override fun startPrimaryUse(delta: Float): Boolean { - return BlockBase.blockStartPrimaryUse(this, i, delta) - } - - override fun effectWhenEquipped(delta: Float) { - BlockBase.blockEffectWhenEquipped(delta) - } - } + if (BlockCodex[tile.id].isWallable) { + ItemCodex["wall@" + tile.id] = makeNewItemObj(tile, true) + if (IS_DEVELOPMENT_BUILD) print("wall@" + tile.id + " ") } } @@ -89,6 +69,32 @@ class EntryPoint : ModuleEntryPoint() { println("[Basegame.EntryPoint] Welcome back!") } + private fun makeNewItemObj(tile: BlockProp, isWall: Boolean) = object : GameItem( + if (isWall) "wall@"+tile.id else tile.id + ) { + override val isUnique: Boolean = false + override var baseMass: Double = tile.density / 1000.0 + override var baseToolSize: Double? = null + override val originalName = tile.nameKey + override var stackable = true + override var inventoryCategory = if (isWall) Category.WALL else Category.BLOCK + override var isDynamic = false + override val material = MaterialCodex.getOrDefault(tile.material) + + init { + equipPosition = EquipPosition.HAND_GRIP + } + + override fun startPrimaryUse(delta: Float): Boolean { + return BlockBase.blockStartPrimaryUse(this, dynamicID, delta) + } + + override fun effectWhenEquipped(delta: Float) { + BlockBase.blockEffectWhenEquipped(delta) + } + } + + override fun dispose() { WatchFont.dispose() } diff --git a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt index cd44d0342..ae72fb9c4 100644 --- a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt +++ b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt @@ -399,6 +399,8 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) { }// END enter override fun worldPrimaryClickStart(delta: Float) { + //println("[Ingame] worldPrimaryClickStart $delta") + // bring up the UIs of the fixtures (e.g. crafting menu from a crafting table) var uiOpened = false diff --git a/src/net/torvald/terrarum/modulebasegame/WorldgenLoadScreen.kt b/src/net/torvald/terrarum/modulebasegame/WorldgenLoadScreen.kt index 8e3ab1551..8a36f2663 100644 --- a/src/net/torvald/terrarum/modulebasegame/WorldgenLoadScreen.kt +++ b/src/net/torvald/terrarum/modulebasegame/WorldgenLoadScreen.kt @@ -7,6 +7,8 @@ import com.badlogic.gdx.graphics.Pixmap import com.badlogic.gdx.graphics.Texture import net.torvald.terrarum.* import net.torvald.terrarum.AppLoader.printdbg +import net.torvald.terrarum.blockproperties.BlockCodex +import net.torvald.terrarum.blockproperties.BlockProp import net.torvald.terrarum.gameworld.GameWorld import net.torvald.util.CircularArray import kotlin.math.roundToInt @@ -93,7 +95,9 @@ class WorldgenLoadScreen(screenToBeLoaded: IngameInstance, private val worldwidt val wx = (world.width.toFloat() / previewWidth * x).roundToInt() val wy = (world.height.toFloat() / previewHeight * y).roundToInt() - val outCol = if (world.getTileFromTerrain(wx, wy) > 15) COL_TERR else if (world.getTileFromWall(wx, wy) > 15) COL_WALLED else COL_AIR + val outCol = if (BlockCodex[world.getTileFromTerrain(wx, wy)].isSolid) COL_TERR + else if (BlockCodex[world.getTileFromWall(wx, wy)].isSolid) COL_WALLED + else COL_AIR previewPixmap.setColor(outCol) previewPixmap.drawPixel(x, previewHeight - 1 - y) // this flips Y diff --git a/src/net/torvald/terrarum/modulebasegame/console/ExportMap.kt b/src/net/torvald/terrarum/modulebasegame/console/ExportMap.kt index f4f159c3a..83be6c6bb 100644 --- a/src/net/torvald/terrarum/modulebasegame/console/ExportMap.kt +++ b/src/net/torvald/terrarum/modulebasegame/console/ExportMap.kt @@ -1,5 +1,6 @@ package net.torvald.terrarum.modulebasegame.console +import net.torvald.gdx.graphics.Cvec import net.torvald.terrarum.AppLoader import net.torvald.terrarum.Terrarum import net.torvald.terrarum.console.ConsoleCommand @@ -7,6 +8,7 @@ import net.torvald.terrarum.console.Echo import net.torvald.terrarum.console.EchoError import net.torvald.terrarum.utils.RasterWriter import net.torvald.terrarum.worlddrawer.CreateTileAtlas +import net.torvald.terrarum.worlddrawer.toRGBA import java.io.File import java.io.IOException @@ -31,7 +33,8 @@ internal object ExportMap : ConsoleCommand { var mapDataPointer = 0 for (tile in world.terrainIterator()) { - val colArray = CreateTileAtlas.terrainTileColourMap.getRaw(tile % 16, tile / 16).toByteArray() + val tileNumber = CreateTileAtlas.tileIDtoItemSheetNumber(tile) + val colArray = CreateTileAtlas.terrainTileColourMap.get(tileNumber)!!.toByteArray() for (i in 0..2) { mapData[mapDataPointer + i] = colArray[i] @@ -71,11 +74,13 @@ internal object ExportMap : ConsoleCommand { /*** * R-G-B-A order for RGBA input value */ + private fun Cvec.toByteArray() = this.toRGBA().toByteArray() + private fun Int.toByteArray() = byteArrayOf( - this.shr(24).and(0xff).toByte(), - this.shr(16).and(0xff).toByte(), - this.shr(8).and(0xff).toByte(), - this.and(0xff).toByte() + this.ushr(24).and(255).toByte(), + this.ushr(16).and(255).toByte(), + this.ushr(8).and(255).toByte(), + this.and(255).toByte() ) override fun printUsage() { diff --git a/src/net/torvald/terrarum/modulebasegame/console/Inventory.kt b/src/net/torvald/terrarum/modulebasegame/console/Inventory.kt index 8a38ffec8..dd61357bd 100644 --- a/src/net/torvald/terrarum/modulebasegame/console/Inventory.kt +++ b/src/net/torvald/terrarum/modulebasegame/console/Inventory.kt @@ -4,6 +4,7 @@ import net.torvald.terrarum.Terrarum import net.torvald.terrarum.console.ConsoleCommand import net.torvald.terrarum.console.Echo import net.torvald.terrarum.console.EchoError +import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.itemproperties.ItemCodex import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.modulebasegame.gameactors.Pocketed @@ -22,10 +23,10 @@ internal object Inventory : ConsoleCommand { else { when (args[1]) { "list" -> listInventory() - "add" -> if (args.size > 3) addItem(args[2].toInt(), args[3].toInt()) - else addItem(args[2].toInt()) + "add" -> if (args.size > 3) addItem(args[2], args[3].toInt()) + else addItem(args[2]) "target" -> setTarget(args[2].toInt()) - "equip" -> equipItem(args[2].toInt()) + "equip" -> equipItem(args[2]) else -> printUsage() } } @@ -57,13 +58,13 @@ internal object Inventory : ConsoleCommand { } } - private fun addItem(refId: Int, amount: Int = 1) { + private fun addItem(refId: ItemID, amount: Int = 1) { if (target != null) { target!!.addItem(ItemCodex[refId]!!, amount) } } - private fun equipItem(refId: Int) { + private fun equipItem(refId: ItemID) { if (target != null) { val item = ItemCodex[refId]!! target!!.equipItem(item) diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/ActorHumanoid.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/ActorHumanoid.kt index c7d9346b2..85ce5eb42 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/ActorHumanoid.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/ActorHumanoid.kt @@ -168,7 +168,7 @@ open class ActorHumanoid( private var jumpJustPressedLatched = false - @Transient private val nullItem = object : GameItem(0) { + @Transient private val nullItem = object : GameItem("item@basegame:0") { override val isUnique: Boolean = false override var baseMass: Double = 0.0 override var baseToolSize: Double? = null diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/ActorInventory.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/ActorInventory.kt index a9a8d57d5..d557c27e9 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/ActorInventory.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/ActorInventory.kt @@ -7,12 +7,11 @@ import net.torvald.terrarum.gameactors.AVKey import net.torvald.terrarum.gameactors.Actor import net.torvald.terrarum.gameitem.GameItem import net.torvald.terrarum.itemproperties.ItemCodex -import net.torvald.terrarum.itemproperties.ItemCodex.ITEM_DYNAMIC -import net.torvald.terrarum.itemproperties.ItemCodex.ITEM_WALLS import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.lock import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.modulebasegame.ui.UIQuickslotBar +import java.math.BigInteger import java.util.* import java.util.concurrent.locks.ReentrantLock @@ -41,23 +40,20 @@ class ActorInventory(@Transient val actor: Pocketed, var maxCapacity: Int, var c val itemList = ArrayList() val quickSlot = Array(UIQuickslotBar.SLOT_COUNT) { null } // 0: Slot 1, 9: Slot 10 - var wallet = 0 // unified currency for whole civs; Dwarf Fortress approach seems too complicated + var wallet = BigInteger("0") // unified currency for whole civs; Dwarf Fortress approach seems too complicated init { } - fun add(itemID: ItemID, count: Int = 1) = add(ItemCodex[itemID]!!, count) + fun add(itemID: ItemID, count: Int = 1) { + if (ItemCodex[itemID] == null) + throw NullPointerException("Item not found: $itemID") + else + add(ItemCodex[itemID]!!, count) + } fun add(item: GameItem, count: Int = 1) { - println("[ActorInventory] add $item, $count") - - - // not wall-able walls - if (item.inventoryCategory == GameItem.Category.WALL && - !BlockCodex[item.dynamicID - ITEM_WALLS.start].isWallable) { - throw IllegalArgumentException("Wall ID ${item.dynamicID - ITEM_WALLS.start} is not wall-able.") - } - + println("[ActorInventory] add-by-elem $item, $count") // other invalid values if (count == 0) @@ -65,12 +61,12 @@ class ActorInventory(@Transient val actor: Pocketed, var maxCapacity: Int, var c if (count < 0) throw IllegalArgumentException("Item count is negative number. If you intended removing items, use remove()\n" + "These commands are NOT INTERCHANGEABLE; they handle things differently according to the context.") - if (item.originalID == Terrarum.PLAYER_REF_ID || item.originalID == 0x51621D) // do not delete this magic + if (item.originalID == "actor:${Terrarum.PLAYER_REF_ID}" || item.originalID == ("actor:${0x51621D}")) // do not delete this magic throw IllegalArgumentException("Attempted to put human player into the inventory.") if (((Terrarum.ingame as? TerrarumIngame)?.gameFullyLoaded ?: false) && - (item.originalID == (Terrarum.ingame as? TerrarumIngame)?.actorNowPlaying?.referenceID)) + (item.originalID == "actor:${(Terrarum.ingame as? TerrarumIngame)?.actorNowPlaying?.referenceID}")) throw IllegalArgumentException("Attempted to put active player into the inventory.") - if ((!item.stackable || item.dynamicID in ITEM_DYNAMIC) && count > 1) + if ((!item.stackable || item.dynamicID.startsWith("dyn:")) && count > 1) throw IllegalArgumentException("Attempting to adding stack of item but the item is not stackable; item: $item, count: $count") diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/DroppedItem.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/DroppedItem.kt index 79ecc61e5..1a7285eca 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/DroppedItem.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/DroppedItem.kt @@ -14,15 +14,15 @@ import net.torvald.terrarum.itemproperties.ItemCodex open class DroppedItem(private val item: GameItem) : ActorWithBody(RenderOrder.MIDTOP, PhysProperties.PHYSICS_OBJECT) { init { - if (item.dynamicID >= ItemCodex.ACTORID_MIN) + if (item.dynamicID.startsWith("actor@")) throw RuntimeException("Attempted to create DroppedItem actor of a real actor; the real actor must be dropped instead.") isVisible = true - avBaseMass = if (item.dynamicID < BlockCodex.MAX_TERRAIN_TILES) - BlockCodex[item.dynamicID].density / 1000.0 - else + avBaseMass = if (item.dynamicID.startsWith("item@")) ItemCodex[item.dynamicID]!!.mass + else + BlockCodex[item.dynamicID].density / 1000.0 // block and wall actorValue[AVKey.SCALE] = ItemCodex[item.dynamicID]!!.scale } diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureBase.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureBase.kt index 5ea16af02..46ccbcddf 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureBase.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureBase.kt @@ -7,6 +7,7 @@ import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.gameactors.ActorWithBody import net.torvald.terrarum.gameactors.PhysProperties +import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.ui.UICanvas @@ -77,10 +78,10 @@ open class FixtureBase( // if the collision type is allow_move_down, only the top surface tile should be "the platform" // lower part must not have such property (think of the table!) // TODO does this ACTUALLY work ?! - world.setTileTerrain(x, y, if (y == posY) BlockBox.ALLOW_MOVE_DOWN else BlockBox.NO_COLLISION) + world.setTileTerrain(x, y, if (y == posY) BlockBox.ALLOW_MOVE_DOWN else BlockBox.NO_COLLISION, false) } else - world.setTileTerrain(x, y, blockBox.collisionType) + world.setTileTerrain(x, y, blockBox.collisionType, false) } } @@ -115,7 +116,7 @@ open class FixtureBase( // remove filler block for (x in posX until posX + blockBox.width) { for (y in posY until posY + blockBox.height) { - world.setTileTerrain(x, y, Block.AIR) + world.setTileTerrain(x, y, Block.AIR, false) } } @@ -156,7 +157,7 @@ open class FixtureBase( for (x in posX until posX + blockBox.width) { for (y in posY until posY + blockBox.height) { if (world.getTileFromTerrain(x, y) == blockBox.collisionType) { - world.setTileTerrain(x, y, Block.AIR) + world.setTileTerrain(x, y, Block.AIR, false) } } } @@ -201,7 +202,7 @@ inline class BlockBoxProps(val flags: Int) { * @param width Width of the block box, tile-wise * @param height Height of the block box, tile-wise */ -data class BlockBox(val collisionType: Int, val width: Int, val height: Int) { +data class BlockBox(val collisionType: ItemID, val width: Int, val height: Int) { /*fun redefine(collisionType: Int, width: Int, height: Int) { redefine(collisionType) diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/HumanoidNPC.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/HumanoidNPC.kt index f01e52aa0..ed1a4ca53 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/HumanoidNPC.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/HumanoidNPC.kt @@ -27,7 +27,7 @@ open class HumanoidNPC( } // we're having GameItem data so that this class could be somewhat universal - override var itemData: GameItem = object : GameItem(referenceID) {//GameItem(referenceID ?: forceAssignRefID!!) { + override var itemData: GameItem = object : GameItem("actor:"+referenceID) {//GameItem(referenceID ?: forceAssignRefID!!) { override val isUnique = true override var baseMass: Double get() = actorValue.getAsDouble(AVKey.BASEMASS)!! diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderSigrid.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderSigrid.kt index 9cdad7f70..6c4cab1d7 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderSigrid.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/PlayerBuilderSigrid.kt @@ -2,7 +2,6 @@ package net.torvald.terrarum.modulebasegame.gameactors import net.torvald.terrarum.ModMgr import net.torvald.terrarum.blockproperties.BlockCodex -import net.torvald.terrarum.blockproperties.BlockCodex.MAX_TERRAIN_TILES import net.torvald.terrarum.gameactors.AVKey import net.torvald.terrarum.gameactors.faction.FactionFactory import net.torvald.terrarum.worlddrawer.CreateTileAtlas @@ -78,20 +77,22 @@ object PlayerBuilderSigrid { CreateTileAtlas.tags.forEach { t, _ -> inventory.add(t, 9995) - if (BlockCodex[t].isWallable) { - inventory.add(t + MAX_TERRAIN_TILES, 9995) + try { + inventory.add("wall@"+t, 9995) // this code will try to add nonexisting wall items, do not get surprised with NPEs + } + catch (e: Throwable) { + System.err.println("[PlayerBuilder] $e") } } // item ids are defined in /items/itemid.csv - inventory.add(135168, 16) // copper pick - inventory.add(135169) // iron pick - inventory.add(135170) // steel pick - inventory.add(135171, 9995) // wire piece - inventory.add(135172, 385930603) // test tiki torch - inventory.add(135173, 95) // crafting table - //inventory.add(9000) // TEST water bucket - //inventory.add(9001) // TEST lava bucket + inventory.add("item@basegame:1", 16) // copper pick + inventory.add("item@basegame:2") // iron pick + inventory.add("item@basegame:3") // steel pick + inventory.add("item@basegame:4", 9995) // wire piece + inventory.add("item@basegame:5", 385930603) // test tiki torch + inventory.add("item@basegame:6", 95) // crafting table + } } diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/Pocketed.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/Pocketed.kt index c22d8ab86..f0635e6f4 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/Pocketed.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/Pocketed.kt @@ -77,12 +77,12 @@ interface Pocketed { } fun equipped(itemID: ItemID) = equipped(ItemCodex[itemID]!!) - fun addItem(itemID: Int, count: Int = 1) = inventory.add(ItemCodex[itemID]!!, count) + fun addItem(itemID: ItemID, count: Int = 1) = inventory.add(ItemCodex[itemID]!!, count) fun addItem(item: GameItem, count: Int = 1) = inventory.add(item, count) - fun removeItem(itemID: Int, count: Int = 1) = inventory.remove(ItemCodex[itemID]!!, count) + fun removeItem(itemID: ItemID, count: Int = 1) = inventory.remove(ItemCodex[itemID]!!, count) fun removeItem(item: GameItem, count: Int = 1) = inventory.remove(item, count) fun hasItem(item: GameItem) = inventory.contains(item.dynamicID) - fun hasItem(id: Int) = inventory.contains(id) + fun hasItem(id: ItemID) = inventory.contains(id) } \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/gameitems/BlockBase.kt b/src/net/torvald/terrarum/modulebasegame/gameitems/BlockBase.kt index 345a8db2f..dd9c8db98 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameitems/BlockBase.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameitems/BlockBase.kt @@ -5,6 +5,7 @@ import net.torvald.terrarum.Point2i import net.torvald.terrarum.Terrarum import net.torvald.terrarum.gameactors.ActorWithBody import net.torvald.terrarum.gameitem.GameItem +import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.itemproperties.ItemCodex import net.torvald.terrarum.modulebasegame.TerrarumIngame @@ -20,7 +21,7 @@ object BlockBase { * @param dontEncaseActors when set to true, blocks won't be placed where Actors are. You will want to set it false * for wire items, otherwise you want it to be true. */ - fun blockStartPrimaryUse(gameItem: GameItem, itemID: Int, delta: Float): Boolean { + fun blockStartPrimaryUse(gameItem: GameItem, itemID: ItemID, delta: Float): Boolean { val ingame = Terrarum.ingame!! as TerrarumIngame val mousePoint = Point2d(Terrarum.mouseTileX.toDouble(), Terrarum.mouseTileY.toDouble()) val mouseTile = Point2i(Terrarum.mouseTileX, Terrarum.mouseTileY) @@ -45,24 +46,26 @@ object BlockBase { if (gameItem.inventoryCategory == GameItem.Category.BLOCK && gameItem.dynamicID == ingame.world.getTileFromTerrain(mouseTile.x, mouseTile.y) || gameItem.inventoryCategory == GameItem.Category.WALL && - gameItem.dynamicID - ItemCodex.ITEM_WALLS.start == ingame.world.getTileFromWall(mouseTile.x, mouseTile.y) - ) + gameItem.dynamicID == ingame.world.getTileFromWall(mouseTile.x, mouseTile.y) + ) return false // filter passed, do the job // FIXME this is only useful for Player - if (itemID in ItemCodex.ITEM_TILES) { - ingame.world.setTileTerrain( - mouseTile.x, - mouseTile.y, - itemID - ) - } - else { + if (itemID.startsWith("wall@")) { ingame.world.setTileWall( mouseTile.x, mouseTile.y, - itemID + itemID.substring(5), + false + ) + } + else { + ingame.world.setTileTerrain( + mouseTile.x, + mouseTile.y, + itemID, + false ) } @@ -74,7 +77,8 @@ object BlockBase { } fun wireStartPrimaryUse(gameItem: GameItem, wireTypeBit: Int, delta: Float): Boolean { - val ingame = Terrarum.ingame!! as TerrarumIngame + return false // TODO need new wire storing format + /*val ingame = Terrarum.ingame!! as TerrarumIngame val mouseTile = Point2i(Terrarum.mouseTileX, Terrarum.mouseTileY) // return false if the tile is already there @@ -93,7 +97,7 @@ object BlockBase { ) ) - return true + return true*/ } fun wireEffectWhenEquipped(typebit: Int, delta: Float) { diff --git a/src/net/torvald/terrarum/modulebasegame/gameworld/WorldSimulator.kt b/src/net/torvald/terrarum/modulebasegame/gameworld/WorldSimulator.kt index 746e26713..6dc6585d1 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameworld/WorldSimulator.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameworld/WorldSimulator.kt @@ -7,6 +7,7 @@ import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.blockproperties.Fluid import net.torvald.terrarum.gameactors.ActorWithBody import net.torvald.terrarum.gamecontroller.KeyToggler +import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.gameworld.FluidType import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid @@ -207,8 +208,8 @@ object WorldSimulator { // process the gradual falling of the selected "stack" if (!fallableStackProcessed && fallDownCounter != 0 && isFallable) { // replace blocks - world.setTileTerrain(x, y, Block.AIR) - world.setTileTerrain(x, y + fallDownCounter, currentTile) + world.setTileTerrain(x, y, Block.AIR, true) + world.setTileTerrain(x, y + fallDownCounter, currentTile, true) fallableStackProcessed = true } @@ -416,7 +417,7 @@ object WorldSimulator { } - fun Int.isFallable() = BlockCodex[this].maxSupport + fun ItemID.isFallable() = BlockCodex[this].maxSupport private val actorMBRConverter = object : MBRConverter { diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIBuildingMakerBlockChooser.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIBuildingMakerBlockChooser.kt index ebd246121..1ad8fdcc4 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIBuildingMakerBlockChooser.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UIBuildingMakerBlockChooser.kt @@ -6,6 +6,7 @@ import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.g2d.SpriteBatch import net.torvald.terrarum.AppLoader import net.torvald.terrarum.blendNormal +import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.fillRect import net.torvald.terrarum.itemproperties.ItemCodex import net.torvald.terrarum.modulebasegame.BuildingMaker @@ -14,6 +15,7 @@ import net.torvald.terrarum.ui.UICanvas import net.torvald.terrarum.ui.UIItemImageButton import net.torvald.terrarum.ui.UIItemTextButtonList import net.torvald.terrarum.ui.UIItemTextButtonList.Companion.DEFAULT_BACKGROUNDCOL +import net.torvald.terrarum.worlddrawer.CreateTileAtlas import kotlin.math.roundToInt /** @@ -37,19 +39,10 @@ class UIBuildingMakerBlockChooser(val parent: BuildingMaker): UICanvas() { override var height = HEIGHT override var openCloseTime = 0f - private val palette = Array(TILES_X * TILES_Y) { - // initialise with terrain blocks - UIItemImageButton( - this, ItemCodex.getItemImage(it), - initialX = MENUBAR_SIZE + (it % 16) * TILESREGION_SIZE, - initialY = (it / 16) * TILESREGION_SIZE, - highlightable = false, - width = TILESREGION_SIZE, - height = TILESREGION_SIZE, - highlightCol = Color.WHITE, - activeCol = Color.WHITE - ) - } + val palette = ArrayList() + + // TODO scrolling of the palette, as the old method flat out won't work with The Flattening + private val tabs = UIItemTextButtonList( this, arrayOf("Terrain", "Wall", "Wire"), 0, 0, textAreaWidth = MENUBAR_SIZE, width = MENUBAR_SIZE, @@ -62,12 +55,25 @@ class UIBuildingMakerBlockChooser(val parent: BuildingMaker): UICanvas() { ) init { - palette.forEachIndexed { index, it -> - uiItems.add(it) - it.clickOnceListener = { _, _, _ -> - parent.setPencilColour(paletteScroll * 16 + index) + BlockCodex.getAll().forEachIndexed { index, prop -> + val paletteItem = UIItemImageButton( + this, ItemCodex.getItemImage(prop.id)!!, + initialX = MENUBAR_SIZE + (index % 16) * TILESREGION_SIZE, + initialY = (index / 16) * TILESREGION_SIZE, + highlightable = false, + width = TILESREGION_SIZE, + height = TILESREGION_SIZE, + highlightCol = Color.WHITE, + activeCol = Color.WHITE + ) + + paletteItem.clickOnceListener = { _, _, _ -> + parent.setPencilColour(prop.id) } + + uiItems.add(paletteItem) + palette.add(paletteItem) } } @@ -119,9 +125,7 @@ class UIBuildingMakerBlockChooser(val parent: BuildingMaker): UICanvas() { } private fun rebuildPalette() { - palette.forEachIndexed { index, it -> - it.image = ItemCodex.getItemImage(paletteScroll * 16 + index) - } + } override fun renderUI(batch: SpriteBatch, camera: Camera) { diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIBuildingMakerPenMenu.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIBuildingMakerPenMenu.kt index d665ce201..be09a9a4f 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIBuildingMakerPenMenu.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UIBuildingMakerPenMenu.kt @@ -153,7 +153,7 @@ class UIBuildingMakerPenMenu(val parent: BuildingMaker): UICanvas() { // draw blocks slot batch.color = blockCellCol - val slotConfig = AppLoader.getConfigIntArray("buildingmakerfavs") + val slotConfig = AppLoader.getConfigStringArray("buildingmakerfavs") for (i in 0 until PALETTE_SIZE) { val x = blockCellPos[i].x.roundToInt().toFloat() val y = blockCellPos[i].y.roundToInt().toFloat() diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIPaletteSelector.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIPaletteSelector.kt index e5d5d9d69..65b446bc6 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIPaletteSelector.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UIPaletteSelector.kt @@ -9,6 +9,7 @@ import net.torvald.terrarum.AppLoader import net.torvald.terrarum.blendNormal import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.fillRect +import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.itemproperties.ItemCodex import net.torvald.terrarum.modulebasegame.BuildingMaker import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory.CELLCOLOUR_BLACK @@ -31,8 +32,8 @@ class UIPaletteSelector(val parent: BuildingMaker) : UICanvas() { fun mouseOnTitleBar() = relativeMouseX in 0 until width && relativeMouseY in 0 until LINE_HEIGHT - var fore = Block.STONE_BRICKS - var back = Block.GLASS_CRUDE + var fore: ItemID = Block.STONE_BRICKS + var back: ItemID = Block.GLASS_CRUDE private val titleText = "Pal." @@ -102,10 +103,9 @@ class UIPaletteSelector(val parent: BuildingMaker) : UICanvas() { } fun swapForeAndBack() { - // xor used, because why not? - fore = fore xor back - back = back xor fore - fore = fore xor back + val t = fore + fore = back + back = t } override fun doOpening(delta: Float) { diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Biomegen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Biomegen.kt index f9e4643fd..43ce0d24f 100644 --- a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Biomegen.kt +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Biomegen.kt @@ -86,17 +86,17 @@ class Biomegen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, par when (control) { 0 -> { // woodlands if (tileThis == Block.DIRT && nearbyTerr.any { it == Block.AIR } && nearbyWall.any { it == Block.AIR }) { - world.setTileTerrain(x, y, Block.GRASS) + world.setTileTerrain(x, y, Block.GRASS, true) } } 1 -> { // shrublands if (tileThis == Block.DIRT && nearbyTerr.any { it == Block.AIR } && nearbyWall.any { it == Block.AIR }) { - world.setTileTerrain(x, y, Block.GRASS) + world.setTileTerrain(x, y, Block.GRASS, true) } } 2, 3 -> { // plains if (tileThis == Block.DIRT && nearbyTerr.any { it == Block.AIR } && nearbyWall.any { it == Block.AIR }) { - world.setTileTerrain(x, y, Block.GRASS) + world.setTileTerrain(x, y, Block.GRASS, true) } } /*3 -> { // sands @@ -109,8 +109,8 @@ class Biomegen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, par }*/ 4 -> { // rockylands if (tileThis == Block.DIRT) { - world.setTileTerrain(x, y, Block.STONE) - world.setTileWall(x, y, Block.STONE) + world.setTileTerrain(x, y, Block.STONE, true) + world.setTileWall(x, y, Block.STONE, true) } } } diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt index 3c47cca21..8d32538b7 100644 --- a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt @@ -28,8 +28,8 @@ class Terragen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, par (0 until world.width).sliceEvenly(genSlices).mapIndexed { i, xs -> ThreadExecutor.submit { val localJoise = getGenerator(seed, params as TerragenParams) - val localLock = java.lang.Object() // in an attempt to fix the "premature exit" issue of a thread run - synchronized(localLock) { // also see: https://stackoverflow.com/questions/28818494/threads-stopping-prematurely-for-certain-values + //val localLock = java.lang.Object() // in an attempt to fix the "premature exit" issue of a thread run + //synchronized(localLock) { // also see: https://stackoverflow.com/questions/28818494/threads-stopping-prematurely-for-certain-values for (x in xs) { for (y in 0 until world.height) { val sampleTheta = (x.toDouble() / world.width) * TWO_PI @@ -43,7 +43,7 @@ class Terragen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, par draw(x, y, noise, world) } } - } + //} } } @@ -69,10 +69,10 @@ class Terragen(world: GameWorld, seed: Long, params: Any) : Gen(world, seed, par val cave = if (noiseValue[1] < 0.5) 0 else 1 val wallBlock = groundDepthBlock[terr] - val terrBlock = wallBlock * cave // AIR is always zero, this is the standard + val terrBlock = if (cave == 0) Block.AIR else wallBlock //wallBlock * cave // AIR is always zero, this is the standard - world.setTileTerrain(x, y, terrBlock) - world.setTileWall(x, y, wallBlock) + world.setTileTerrain(x, y, terrBlock, true) + world.setTileWall(x, y, wallBlock, true) } diff --git a/src/net/torvald/terrarum/serialise/ReadLayerDataLzma.kt b/src/net/torvald/terrarum/serialise/ReadLayerDataLzma.kt index 248694795..d5cd4a57e 100644 --- a/src/net/torvald/terrarum/serialise/ReadLayerDataLzma.kt +++ b/src/net/torvald/terrarum/serialise/ReadLayerDataLzma.kt @@ -2,6 +2,7 @@ package net.torvald.terrarum.serialise import com.badlogic.gdx.utils.compression.Lzma import net.torvald.terrarum.AppLoader.printdbg +import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.gameworld.BlockAddress import net.torvald.terrarum.gameworld.BlockLayer import net.torvald.terrarum.gameworld.FluidType @@ -151,6 +152,7 @@ internal object ReadLayerDataLzma { val wallDamages = HashMap() val fluidTypes = HashMap() val fluidFills = HashMap() + val tileNumToName = HashMap() // parse terrain damages for (c in payloadBytes["TdMG"]!!.indices step 10) { @@ -176,6 +178,8 @@ internal object ReadLayerDataLzma { // TODO parse fluid(Types|Fills) + // TODO parse tileNumToName + return ReadLayerDataZip.LayerData( BlockLayer(width, height, payloadBytes["WALL"]!!), @@ -183,7 +187,7 @@ internal object ReadLayerDataLzma { spawnPoint.first, spawnPoint.second, - wallDamages, terrainDamages, fluidTypes, fluidFills + wallDamages, terrainDamages, fluidTypes, fluidFills, tileNumToName ) } diff --git a/src/net/torvald/terrarum/serialise/ReadLayerDataZip.kt b/src/net/torvald/terrarum/serialise/ReadLayerDataZip.kt index e166e9eae..b145aa682 100644 --- a/src/net/torvald/terrarum/serialise/ReadLayerDataZip.kt +++ b/src/net/torvald/terrarum/serialise/ReadLayerDataZip.kt @@ -1,6 +1,7 @@ package net.torvald.terrarum.serialise import net.torvald.terrarum.AppLoader.printdbg +import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.gameworld.BlockAddress import net.torvald.terrarum.gameworld.BlockLayer import net.torvald.terrarum.gameworld.FluidType @@ -152,6 +153,7 @@ internal object ReadLayerDataZip { val wallDamages = HashMap() val fluidTypes = HashMap() val fluidFills = HashMap() + val tileNumberToNameMap = HashMap() // parse terrain damages for (c in payloadBytes["TdMG"]!!.indices step 10) { @@ -184,7 +186,7 @@ internal object ReadLayerDataZip { spawnPoint.first, spawnPoint.second, - wallDamages, terrainDamages, fluidTypes, fluidFills + wallDamages, terrainDamages, fluidTypes, fluidFills, tileNumberToNameMap ) } @@ -204,7 +206,8 @@ internal object ReadLayerDataZip { val wallDamages: HashMap, val terrainDamages: HashMap, val fluidTypes: HashMap, - val fluidFills: HashMap + val fluidFills: HashMap, + val tileNumberToNameMap: HashMap ) internal fun InputStream.readRelative(b: ByteArray, off: Int, len: Int): Int { diff --git a/src/net/torvald/terrarum/serialise/SavegameWriter.kt b/src/net/torvald/terrarum/serialise/SavegameWriter.kt index cf495f13b..50c3aa53d 100644 --- a/src/net/torvald/terrarum/serialise/SavegameWriter.kt +++ b/src/net/torvald/terrarum/serialise/SavegameWriter.kt @@ -1,6 +1,7 @@ package net.torvald.terrarum.serialise import com.badlogic.gdx.Gdx +import net.torvald.random.HQRNG import net.torvald.terrarum.AppLoader import net.torvald.terrarum.Terrarum import net.torvald.terrarum.gameactors.AVKey @@ -9,10 +10,31 @@ import net.torvald.terrarum.gameitem.GameItem import net.torvald.terrarum.itemproperties.ItemCodex import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.* import net.torvald.terrarum.utils.JsonWriter.getJsonBuilder +import net.torvald.util.SortedArrayList import java.io.File import java.nio.charset.Charset import kotlin.math.roundToInt +internal class RNGPool() { + private val RNG = HQRNG() + private val used = SortedArrayList() + + init { + for (i in 0 until 32767) { + used.add(i) + } + } + + fun next(): Int { + var n = RNG.nextLong().ushr(32).toInt() + while (used.contains(n)) { + n = RNG.nextLong().ushr(32).toInt() + } + used.add(n) + return n + } +} + /** * Created by minjaesong on 2018-10-03. */ @@ -20,6 +42,8 @@ object SavegameWriter { // TODO create temporary files (worldinfo), create JSON files on RAM, pack those into TEVd as per Savegame container.txt + private val rngPool = RNGPool() + private val charset = Charset.forName("UTF-8") private lateinit var playerName: String @@ -99,16 +123,16 @@ object SavegameWriter { // actors ingame.actorContainerActive.forEach { VDUtil.registerFile(disk, DiskEntry( - it.referenceID!!, ROOT, - it.referenceID!!.toString(16).toUpperCase().toByteArray(charset), + rngPool.next(), ROOT, + it.referenceID.toString(16).toUpperCase().toByteArray(charset), creationDate, creationDate, EntryFile(serialiseActor(it)) )) } ingame.actorContainerInactive.forEach { VDUtil.registerFile(disk, DiskEntry( - it.referenceID!!, ROOT, - it.referenceID!!.toString(16).toUpperCase().toByteArray(charset), + rngPool.next(), ROOT, + it.referenceID.toString(16).toUpperCase().toByteArray(charset), creationDate, creationDate, EntryFile(serialiseActor(it)) )) @@ -117,8 +141,8 @@ object SavegameWriter { // items ItemCodex.dynamicItemDescription.forEach { dynamicID, item -> VDUtil.registerFile(disk, DiskEntry( - item.dynamicID, ROOT, - dynamicID.toString(16).toUpperCase().toByteArray(charset), + rngPool.next(), ROOT, + dynamicID.toByteArray(charset), creationDate, creationDate, EntryFile(serialiseItem(item)) )) diff --git a/src/net/torvald/terrarum/serialise/WriteWorldInfo.kt b/src/net/torvald/terrarum/serialise/WriteWorldInfo.kt index af9096505..f3cf8b6fb 100644 --- a/src/net/torvald/terrarum/serialise/WriteWorldInfo.kt +++ b/src/net/torvald/terrarum/serialise/WriteWorldInfo.kt @@ -52,8 +52,8 @@ object WriteWorldInfo { val infile = infileList[filenum - 1] infile.forEach { - outputStream.write("## from file: ${it.nameWithoutExtension()} ##############################\n".toByteArray()) - val readBytes = it.readBytes() + outputStream.write("## from file: ${it.second.nameWithoutExtension()} ##############################\n".toByteArray()) + val readBytes = it.second.readBytes() outputStream.write(readBytes) outputStream.write("\n".toByteArray()) } diff --git a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt index bcbecb7e9..7a061b719 100644 --- a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt +++ b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt @@ -161,7 +161,7 @@ class BasicDebugInfoWindow : UICanvas() { val wireNum = ingame!!.world.getWiringBlocks(mouseTileX, mouseTileY) val fluid = ingame!!.world.getFluid(mouseTileX, mouseTileY) - printLine(batch, 9, "tile@cursor ${ccO}W$ccG$wallNum ${ccO}T$ccG$tileNum ${ccO}C$ccG${wireNum.toString(2)} $ccY($mtX, $mtY)") + printLine(batch, 9, "tile@cursor ${ccO}W$ccG$wallNum ${ccO}T$ccG$tileNum ${ccO}C$ccG${wireNum} $ccY($mtX, $mtY)") printLine(batch, 10, "fluid@cursor ${ccO}Type $ccG${fluid.type.value} ${ccO}Fill $ccG${fluid.amount}f") } diff --git a/src/net/torvald/terrarum/utils/PasswordBase32.kt b/src/net/torvald/terrarum/utils/PasswordBase32.kt index d35522976..6f151f26a 100644 --- a/src/net/torvald/terrarum/utils/PasswordBase32.kt +++ b/src/net/torvald/terrarum/utils/PasswordBase32.kt @@ -10,7 +10,7 @@ import kotlin.experimental.xor */ object PasswordBase32 { - private val stringSet = "YBNDRFG8EJKMCPQXOT+VWIS2A345H769=" + private val stringSet = "YBNDRFG8EJKMCPQXOTLVWIS2A345H769=" private val substituteSet = hashMapOf( Pair('0', 'O'), diff --git a/src/net/torvald/terrarum/worlddrawer/BlocksDrawerNew.kt b/src/net/torvald/terrarum/worlddrawer/BlocksDrawerNew.kt index 925b6ac61..7f7a5ea02 100644 --- a/src/net/torvald/terrarum/worlddrawer/BlocksDrawerNew.kt +++ b/src/net/torvald/terrarum/worlddrawer/BlocksDrawerNew.kt @@ -8,6 +8,7 @@ import net.torvald.terrarum.* import net.torvald.terrarum.AppLoader.printdbg import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.BlockCodex +import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension @@ -54,9 +55,6 @@ internal object BlocksDrawer { //val tileItemWall = Image(TILE_SIZE * 16, TILE_SIZE * GameWorld.TILES_SUPPORTED / 16) // 4 MB - - val wallOverlayColour = Color(5f / 9f, 5f / 9f, 5f / 9f, 1f) - const val BREAKAGE_STEPS = 10 val WALL = GameWorld.WALL @@ -96,23 +94,7 @@ internal object BlocksDrawer { // with TGA, you have a complete control over this, with the expense of added hassle on your side. // -- Torvald, 2018-12-19 - printdbg(this, "Making terrain textures...") - - CreateTileAtlas() - //JsonWriter.writeToFile(CreateTileAtlas.tags, "${AppLoader.defaultDir}/test_rendertags.json") - // each takes about 60 seconds - //printdbg(this, "Writing pixmap as tga: atlas.tga") - //PixmapIO2.writeTGA(Gdx.files.absolute("${AppLoader.defaultDir}/atlas.tga"), CreateTileAtlas.atlas, false) - //printdbg(this, "Writing pixmap as tga: atlasAutumn.tga") - //PixmapIO2.writeTGA(Gdx.files.absolute("${AppLoader.defaultDir}/atlasAutumn.tga"), CreateTileAtlas.atlasAutumn, false) - //printdbg(this, "Writing pixmap as tga: atlasWinter.tga") - //PixmapIO2.writeTGA(Gdx.files.absolute("${AppLoader.defaultDir}/atlasWinter.tga"), CreateTileAtlas.atlasWinter, false) - //printdbg(this, "Writing pixmap as tga: atlasSpring.tga") - //PixmapIO2.writeTGA(Gdx.files.absolute("${AppLoader.defaultDir}/atlasSpring.tga"), CreateTileAtlas.atlasSpring, false) - //printdbg(this, "Writing pixmap as tga: atlasFluid.tga") - //PixmapIO2.writeTGA(Gdx.files.absolute("${AppLoader.defaultDir}/atlasFluid.tga"), CreateTileAtlas.atlasFluid, false) - - + // CreateTileAtlas.invoke() has been moved to the AppLoader.create() // // create terrain texture from pixmaps weatherTerrains = arrayOf( @@ -179,7 +161,7 @@ internal object BlocksDrawer { /** * To interact with external modules */ - @JvmStatic fun addBlendMul(blockID: Int): Boolean { + @JvmStatic fun addBlendMul(blockID: ItemID): Boolean { return TILES_BLEND_MUL.add(blockID) } @@ -307,11 +289,11 @@ internal object BlocksDrawer { val bufferX = x - for_x_start val bufferY = y - for_y_start - val thisTile = when (mode) { + val thisTile: ItemID = when (mode) { WALL -> world.getTileFromWall(x, y) TERRAIN -> world.getTileFromTerrain(x, y) - WIRE -> world.getWiringBlocks(x, y).and(drawWires).toBitOrd() * 16 - FLUID -> world.getFluid(x, y).type.abs() + WIRE -> "basegame:-1" // TODO need new wire storing format //world.getWiringBlocks(x, y).and(drawWires).toBitOrd() * 16 + FLUID -> "basegame:-1" // TODO need new wire storing format //world.getFluid(x, y).type.abs() else -> throw IllegalArgumentException() } @@ -344,10 +326,10 @@ internal object BlocksDrawer { if (mode == FLUID) CreateTileAtlas.fluidToTileNumber(world.getFluid(x, y)) else if (mode == WIRE) - thisTile + 0 // TODO need new wire storing format else renderTag.tileNumber - val tileNumber = if (mode != WIRE && thisTile == 0) 0 + val tileNumber = if (mode != WIRE && thisTile == Block.AIR) 0 // special case: fluids else if (mode == FLUID) tileNumberBase + connectLut47[nearbyTilesInfo] // special case: wires @@ -376,11 +358,11 @@ internal object BlocksDrawer { // draw a tile - if (mode == WIRE && thisTile < 0) { + if (mode == WIRE) { // no wire here, draw block id 255 (bottom right) writeToBuffer(mode, bufferX, bufferY, 15, 15, 0) } - else if (mode == FLUID || mode == WIRE) { + else if (mode == FLUID) { writeToBuffer(mode, bufferX, bufferY, thisTileX, thisTileY, 0) } else { @@ -404,7 +386,7 @@ internal object BlocksDrawer { ) } - private fun getNearbyTilesInfoConSelf(x: Int, y: Int, mode: Int, mark: Int?): Int { + private fun getNearbyTilesInfoConSelf(x: Int, y: Int, mode: Int, mark: ItemID?): Int { val nearbyTiles = getNearbyTilesPos(x, y).map { world.getTileFrom(mode, it.x, it.y) ?: Block.NULL } var ret = 0 @@ -423,8 +405,9 @@ internal object BlocksDrawer { * * @return offset from the spritesheet's "base" tile number, 0..15. */ - private fun getNearbyWiringInfo(x: Int, y: Int, wire: Int): Int { - val nearbyTiles = getNearbyTilesPos(x, y).map { world.getWiringBlocks(it.x, it.y).and(drawWires).toBitOrd() * 16 } + private fun getNearbyWiringInfo(x: Int, y: Int, wire: ItemID): Int { + return 0 // TODO need new wire storing format + /*val nearbyTiles = getNearbyTilesPos(x, y).map { world.getWiringBlocks(it.x, it.y).and(drawWires).toBitOrd() * 16 } var ret = 0 for (i in nearbyTiles.indices) { @@ -433,11 +416,11 @@ internal object BlocksDrawer { } } - return ret + return ret*/ } private fun getNearbyTilesInfoConMutual(x: Int, y: Int, mode: Int): Int { - val nearbyTiles = getNearbyTilesPos(x, y).map { world.getTileFrom(mode, it.x, it.y) ?: Block.NULL } + val nearbyTiles: List = getNearbyTilesPos(x, y).map { world.getTileFrom(mode, it.x, it.y)!! } var ret = 0 for (i in nearbyTiles.indices) { @@ -454,7 +437,7 @@ internal object BlocksDrawer { */ private fun getNearbyTilesInfoFluids(x: Int, y: Int): Int { val nearbyPos = getNearbyTilesPos(x, y) - val nearbyTiles = nearbyPos.map { world.getTileFromTerrain(it.x, it.y) ?: Block.NULL } + val nearbyTiles: List = nearbyPos.map { world.getTileFromTerrain(it.x, it.y) } var ret = 0 for (i in nearbyTiles.indices) { @@ -468,12 +451,12 @@ internal object BlocksDrawer { } private fun getNearbyTilesInfoWallSticker(x: Int, y: Int): Int { - val nearbyTiles = IntArray(4) + val nearbyTiles = arrayOf(Block.NULL, Block.NULL, Block.NULL, Block.NULL) val NEARBY_TILE_KEY_BACK = NEARBY_TILE_KEY_UP - nearbyTiles[NEARBY_TILE_KEY_LEFT] = world.getTileFrom(TERRAIN, x - 1, y) ?: Block.NULL - nearbyTiles[NEARBY_TILE_KEY_RIGHT] = world.getTileFrom(TERRAIN, x + 1, y) ?: Block.NULL - nearbyTiles[NEARBY_TILE_KEY_DOWN] = world.getTileFrom(TERRAIN, x , y + 1) ?: Block.NULL - nearbyTiles[NEARBY_TILE_KEY_BACK] = world.getTileFrom(WALL, x , y) ?: Block.NULL + nearbyTiles[NEARBY_TILE_KEY_LEFT] = world.getTileFrom(TERRAIN, x - 1, y) + nearbyTiles[NEARBY_TILE_KEY_RIGHT] = world.getTileFrom(TERRAIN, x + 1, y) + nearbyTiles[NEARBY_TILE_KEY_DOWN] = world.getTileFrom(TERRAIN, x , y + 1) + nearbyTiles[NEARBY_TILE_KEY_BACK] = world.getTileFrom(WALL, x , y) try { if (BlockCodex[nearbyTiles[NEARBY_TILE_KEY_DOWN]].isSolid) @@ -502,9 +485,11 @@ internal object BlocksDrawer { } private fun getNearbyTilesInfoPlatform(x: Int, y: Int): Int { - val nearbyTiles = IntArray(4) - nearbyTiles[NEARBY_TILE_KEY_LEFT] = world.getTileFrom(TERRAIN, x - 1, y) ?: Block.NULL - nearbyTiles[NEARBY_TILE_KEY_RIGHT] = world.getTileFrom(TERRAIN, x + 1, y) ?: Block.NULL + val nearbyTiles = arrayOf(Block.NULL, Block.NULL, Block.NULL, Block.NULL) + val NEARBY_TILE_KEY_BACK = NEARBY_TILE_KEY_UP + nearbyTiles[NEARBY_TILE_KEY_LEFT] = world.getTileFrom(TERRAIN, x - 1, y) + nearbyTiles[NEARBY_TILE_KEY_LEFT] = world.getTileFrom(TERRAIN, x - 1, y) + nearbyTiles[NEARBY_TILE_KEY_RIGHT] = world.getTileFrom(TERRAIN, x + 1, y) if ((BlockCodex[nearbyTiles[NEARBY_TILE_KEY_LEFT]].isSolid && BlockCodex[nearbyTiles[NEARBY_TILE_KEY_RIGHT]].isSolid) || @@ -594,7 +579,7 @@ internal object BlocksDrawer { } val vertexColour = when (mode) { TERRAIN, WIRE, FLUID -> Color.WHITE - WALL -> wallOverlayColour + WALL -> CreateTileAtlas.wallOverlayColour else -> throw IllegalArgumentException() } @@ -753,10 +738,10 @@ internal object BlocksDrawer { fun getRenderEndX(): Int = clampWTile(getRenderStartX() + (WorldCamera.width / TILE_SIZE) + 2) fun getRenderEndY(): Int = clampHTile(getRenderStartY() + (WorldCamera.height / TILE_SIZE) + 2) - fun isConnectSelf(b: Int): Boolean = CreateTileAtlas.getRenderTag(b).connectionType == CreateTileAtlas.RenderTag.CONNECT_SELF - fun isConnectMutual(b: Int): Boolean = CreateTileAtlas.getRenderTag(b).connectionType == CreateTileAtlas.RenderTag.CONNECT_MUTUAL - fun isWallSticker(b: Int): Boolean = CreateTileAtlas.getRenderTag(b).connectionType == CreateTileAtlas.RenderTag.CONNECT_WALL_STICKER - fun isPlatform(b: Int): Boolean = CreateTileAtlas.getRenderTag(b).connectionType == CreateTileAtlas.RenderTag.CONNECT_WALL_STICKER_CONNECT_SELF + fun isConnectSelf(b: ItemID): Boolean = CreateTileAtlas.getRenderTag(b).connectionType == CreateTileAtlas.RenderTag.CONNECT_SELF + fun isConnectMutual(b: ItemID): Boolean = CreateTileAtlas.getRenderTag(b).connectionType == CreateTileAtlas.RenderTag.CONNECT_MUTUAL + fun isWallSticker(b: ItemID): Boolean = CreateTileAtlas.getRenderTag(b).connectionType == CreateTileAtlas.RenderTag.CONNECT_WALL_STICKER + fun isPlatform(b: ItemID): Boolean = CreateTileAtlas.getRenderTag(b).connectionType == CreateTileAtlas.RenderTag.CONNECT_WALL_STICKER_CONNECT_SELF //fun isBlendMul(b: Int): Boolean = TILES_BLEND_MUL.contains(b) fun tileInCamera(x: Int, y: Int) = diff --git a/src/net/torvald/terrarum/worlddrawer/CreateTileAtlas.kt b/src/net/torvald/terrarum/worlddrawer/CreateTileAtlas.kt index 9dc63e3c7..d426a0054 100644 --- a/src/net/torvald/terrarum/worlddrawer/CreateTileAtlas.kt +++ b/src/net/torvald/terrarum/worlddrawer/CreateTileAtlas.kt @@ -6,9 +6,13 @@ import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Pixmap import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.utils.GdxRuntimeException +import net.torvald.gdx.graphics.Cvec import net.torvald.terrarum.* +import net.torvald.terrarum.AppLoader.printdbg +import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.blockproperties.Fluid +import net.torvald.terrarum.gameitem.ItemID import net.torvald.terrarum.gameworld.GameWorld import kotlin.math.roundToInt @@ -28,8 +32,12 @@ object CreateTileAtlas { const val TILE_SIZE = TerrarumAppConfiguration.TILE_SIZE const val TILES_IN_X = MAX_TEX_SIZE / TILE_SIZE + const val ITEM_ATLAS_TILES_X = 16 + private val TOTAL_TILES = TILES_IN_X * TILES_IN_X + val wallOverlayColour = Color(5f / 9f, 5f / 9f, 5f / 9f, 1f) + lateinit var atlas: Pixmap lateinit var atlasAutumn: Pixmap lateinit var atlasWinter: Pixmap @@ -38,32 +46,31 @@ object CreateTileAtlas { lateinit var atlasGlow: Pixmap // glowing won't be affected by the season... for now lateinit var itemTerrainTexture: Texture lateinit var itemWallTexture: Texture - lateinit var terrainTileColourMap: GdxColorMap - internal lateinit var tags: HashMap + lateinit var terrainTileColourMap: HashMap + lateinit var tags: HashMap // TileID, RenderTag + private set + lateinit var itemSheetNumbers: HashMap // TileID, Int private set private val defaultRenderTag = RenderTag(3, RenderTag.CONNECT_SELF, RenderTag.MASK_NA) // 'update' block var initialised = false private set - /** 0000.tga, 1.tga.gz, 3242423.tga, 000033.tga.gz */ - // for right now, TGA file only, no gzip - private val validFluidTilesFilename = Regex("""fluid_[0-9]+\.tga""") - private val tileNameRegex = Regex("""[0-9]+\.tga""") - private val tileGlowNameRegex = Regex("""[0-9]+_glow\.tga""") + /** 0.tga, 1.tga.gz, 3242423.tga, 33.tga.gz */ + private val tileNameRegex = Regex("""(0|[1-9][0-9]*)\.tga(\.gz)?""") // 16 tiles are reserved for internal use: solid black, solid white, breakage stages. // 0th tile is complete transparent tile and is also a BlockID of zero: air. - private var atlasCursor = 0 - private var atlasCursorGlow = 0 + private var atlasCursor = 64 // 64 predefined tiles. The normal blocks (e.g. Air) should start from this number private val atlasInit = "./assets/graphics/blocks/init.tga" + private var itemSheetCursor = 16 /** * Must be called AFTER mods' loading so that all the block props are loaded */ operator fun invoke(updateExisting: Boolean = false) { if (updateExisting || !initialised) { - tags = HashMap() - tags[0] = RenderTag(0, RenderTag.CONNECT_SELF, RenderTag.MASK_NA) + tags = HashMap() + itemSheetNumbers = HashMap() atlas = Pixmap(TILES_IN_X * TILE_SIZE, TILES_IN_X * TILE_SIZE, Pixmap.Format.RGBA8888) atlasAutumn = Pixmap(TILES_IN_X * TILE_SIZE, TILES_IN_X * TILE_SIZE, Pixmap.Format.RGBA8888) @@ -79,34 +86,39 @@ object CreateTileAtlas { atlasFluid.blending = Pixmap.Blending.None atlasGlow.blending = Pixmap.Blending.None - val initMap = Pixmap(Gdx.files.internal(atlasInit)) - drawToAtlantes(initMap, nullTile, 16) - initMap.dispose() - + // populate the atlantes with atlasInit + // this just directly copies the image to the atlantes :p + val initPixmap = Pixmap(Gdx.files.internal(atlasInit)) + atlas.drawPixmap(initPixmap, 0, 0) + atlasAutumn.drawPixmap(initPixmap, 0, 0) + atlasWinter.drawPixmap(initPixmap, 0, 0) + atlasSpring.drawPixmap(initPixmap, 0, 0) // get all the files applicable // first, get all the '/blocks' directory, and add all the files, regardless of their extension, to the list - val tgaList = ArrayList() - ModMgr.getGdxFilesFromEveryMod("blocks").forEach { - if (!it.isDirectory) { - throw Error("Path '${it.path()}' is not a directory") + val tgaList = ArrayList>() //Pair of + ModMgr.getGdxFilesFromEveryMod("blocks").forEach { (modname, dir) -> + if (!dir.isDirectory) { + throw Error("Path '${dir.path()}' is not a directory") } - it.list().forEach { tgaFile -> - if (!tgaFile.isDirectory && (tgaFile.name().matches(tileNameRegex))) { - tgaList.add(tgaFile) - } - } + + dir.list().filter { tgaFile -> !tgaFile.isDirectory && (tgaFile.name().matches(tileNameRegex)) } + .sortedBy { it.nameWithoutExtension().toInt() }.forEach { tgaFile -> // toInt() to sort by the number, not lexicographically + tgaList.add(modname to tgaFile) + } } // Sift through the file list for blocks, but TGA format first - tgaList.forEach { + tgaList.forEach { (modname, filehandle) -> + printdbg(this, "processing $modname:${filehandle.name()}") + try { - val glowFile = Gdx.files.internal(it.path().dropLast(4) + "_glow.tga") // assuming strict ".tga" file - fileToAtlantes(it, if (glowFile.exists()) glowFile else null) + val glowFile = Gdx.files.internal(filehandle.path().dropLast(4) + "_glow.tga") // assuming strict ".tga" file for now... + fileToAtlantes(modname, filehandle, if (glowFile.exists()) glowFile else null) } catch (e: GdxRuntimeException) { - System.err.println("Couldn't load file $it, skipping...") + System.err.println("Couldn't load file $filehandle from $modname, skipping...") } } @@ -127,73 +139,6 @@ object CreateTileAtlas { } }*/ - - // Sift through the file list for fluids, but TGA format first - val fluidMasterPixmap = Pixmap(TILE_SIZE * 47, TILE_SIZE * 8, Pixmap.Format.RGBA8888) - tgaList.filter { it.name().matches(validFluidTilesFilename) && it.extension().toUpperCase() == "TGA" }.forEachIndexed { fluidLevel, it -> - val pixmap = Pixmap(it) - // dirty manual copy - repeat(5) { - fluidMasterPixmap.drawPixmap(pixmap, - it * TILE_SIZE * 7, fluidLevel * TILE_SIZE, - 0, TILE_SIZE * it, - TILE_SIZE * 7, TILE_SIZE - ) - } - repeat(2) { - fluidMasterPixmap.drawPixmap(pixmap, - (35 + it * 6) * TILE_SIZE, fluidLevel * TILE_SIZE, - 0, TILE_SIZE * (5 + it), - TILE_SIZE * 6, TILE_SIZE - ) - } - - pixmap.dispose() - } - // test print - //PixmapIO2.writeTGA(Gdx.files.absolute("${AppLoader.defaultDir}/fluidpixmapmaster.tga"), fluidMasterPixmap, false) - - // occupy the fluid pixmap with software rendering - for (i in BlockCodex.MAX_TERRAIN_TILES..BlockCodex.highestNumber) { - val fluid = Color(BlockCodex[i].colour) - - // pixmap <- (color SCREEN fluidMasterPixmap) - // then occupy the atlasFluid - val pixmap = Pixmap(fluidMasterPixmap.width, fluidMasterPixmap.height, Pixmap.Format.RGBA8888) - pixmap.blending = Pixmap.Blending.None - - for (y in 0 until pixmap.height) { - for (x in 0 until pixmap.width) { - val inColour = Color(fluidMasterPixmap.getPixel(x, y)) - // SCREEN for RGB, MUL for A. - inColour.r = 1f - (1f - fluid.r) * (1f - inColour.r) - inColour.g = 1f - (1f - fluid.g) * (1f - inColour.g) - inColour.b = 1f - (1f - fluid.b) * (1f - inColour.b) - inColour.a = fluid.a * inColour.a - - pixmap.drawPixel(x, y, inColour.toRGBA()) - } - } - - // test print - //PixmapIO2.writeTGA(Gdx.files.absolute("${AppLoader.defaultDir}/$i.tga"), pixmap, false) - - // to the atlas - val atlasTargetPos = 16 + 47 * 8 * (i - BlockCodex.MAX_TERRAIN_TILES) - for (k in 0 until 47 * 8) { - val srcX = (k % 47) * TILE_SIZE - val srcY = (k / 47) * TILE_SIZE - val destX = ((atlasTargetPos + k) % TILES_IN_X) * TILE_SIZE - val destY = ((atlasTargetPos + k) / TILES_IN_X) * TILE_SIZE - atlasFluid.drawPixmap(pixmap, srcX, srcY, TILE_SIZE, TILE_SIZE, destX, destY, TILE_SIZE, TILE_SIZE) - } - - pixmap.dispose() - } - - - fluidMasterPixmap.dispose() - // create item_wall images fun maskTypetoTileIDForItemImage(maskType: Int) = when(maskType) { @@ -204,62 +149,63 @@ object CreateTileAtlas { val itemTerrainPixmap = Pixmap(16 * TILE_SIZE, TILES_IN_X * TILE_SIZE, Pixmap.Format.RGBA8888) val itemWallPixmap = Pixmap(16 * TILE_SIZE, TILES_IN_X * TILE_SIZE, Pixmap.Format.RGBA8888) - val terrainColormapPixmap = Pixmap(16, TILES_IN_X, Pixmap.Format.RGBA8888) - CreateTileAtlas.tags.toMap().forEach { t, u -> - val tilePosFromAtlas = u.tileNumber + maskTypetoTileIDForItemImage(u.maskType) + CreateTileAtlas.tags.toMap().forEach { id, tag -> + val tilePosFromAtlas = tag.tileNumber + maskTypetoTileIDForItemImage(tag.maskType) val srcX = (tilePosFromAtlas % TILES_IN_X) * TILE_SIZE val srcY = (tilePosFromAtlas / TILES_IN_X) * TILE_SIZE - val destX = (t % 16) * TILE_SIZE - val destY = (t / 16) * TILE_SIZE + val t = tileIDtoItemSheetNumber(id) + val destX = (t % ITEM_ATLAS_TILES_X) * TILE_SIZE + val destY = (t / ITEM_ATLAS_TILES_X) * TILE_SIZE itemTerrainPixmap.drawPixmap(CreateTileAtlas.atlas, srcX, srcY, TILE_SIZE, TILE_SIZE, destX, destY, TILE_SIZE, TILE_SIZE) itemWallPixmap.drawPixmap(CreateTileAtlas.atlas, srcX, srcY, TILE_SIZE, TILE_SIZE, destX, destY, TILE_SIZE, TILE_SIZE) } // darken things for the wall for (y in 0 until itemWallPixmap.height) { for (x in 0 until itemWallPixmap.width) { - val c = Color(itemWallPixmap.getPixel(x, y)).mulAndAssign(BlocksDrawer.wallOverlayColour).toRGBA() + val c = Color(itemWallPixmap.getPixel(x, y)).mulAndAssign(wallOverlayColour).toRGBA() itemWallPixmap.drawPixel(x, y, c) } } + + // create terrain colourmap + terrainTileColourMap = HashMap() val pxCount = TILE_SIZE * TILE_SIZE - for (id in 0 until BlockCodex.MAX_TERRAIN_TILES) { - val tx = (id % 16) * TILE_SIZE - val ty = (id / 16) * TILE_SIZE - var r = 0; var g = 0; var b = 0; var a = 0 + for (id in itemSheetNumbers) { + val tilenum = id.value + val tx = (tilenum % ITEM_ATLAS_TILES_X) * TILE_SIZE + val ty = (tilenum / ITEM_ATLAS_TILES_X) * TILE_SIZE + var r = 0f; var g = 0f; var b = 0f; var a = 0f // average out the whole block for (y in ty until ty + TILE_SIZE) { for (x in tx until tx + TILE_SIZE) { val data = itemTerrainPixmap.getPixel(x, y) - r += (data ushr 24) and 255 - g += (data ushr 16) and 255 - b += (data ushr 8) and 255 - a += data and 255 + r += ((data ushr 24) and 255).div(255f) + g += ((data ushr 16) and 255).div(255f) + b += ((data ushr 8) and 255).div(255f) + a += (data and 255).div(255f) } } - terrainColormapPixmap.drawPixel(tx / TILE_SIZE, ty / TILE_SIZE, - (r / pxCount).shl(24) or - (g / pxCount).shl(16) or - (b / pxCount).shl(8) or - (a / pxCount) + terrainTileColourMap[id.key] = Cvec( + (r / pxCount), + (g / pxCount), + (b / pxCount), + (a / pxCount) ) } - //PixmapIO2.writeTGA(Gdx.files.absolute("${AppLoader.defaultDir}/terrain_colormap.tga"), terrainColormapPixmap, false) - //PixmapIO2.writeTGA(Gdx.files.absolute("${AppLoader.defaultDir}/terrainitem.tga"), itemTerrainPixmap, false) - - terrainTileColourMap = GdxColorMap(terrainColormapPixmap) itemTerrainTexture = Texture(itemTerrainPixmap) itemWallTexture = Texture(itemWallPixmap) itemTerrainPixmap.dispose() itemWallPixmap.dispose() + initPixmap.dispose() initialised = true } } - fun getRenderTag(blockID: Int): RenderTag { + fun getRenderTag(blockID: ItemID): RenderTag { return tags.getOrDefault(blockID, defaultRenderTag) } @@ -271,12 +217,13 @@ object CreateTileAtlas { 16 + (376 * (fluid.type.abs() - 1)) + (47 * (fluidLevel - 1)) } - private val nullTile = Pixmap(TILE_SIZE * 16, TILE_SIZE * 16, Pixmap.Format.RGBA8888) + val nullTile = Pixmap(TILE_SIZE * 16, TILE_SIZE * 16, Pixmap.Format.RGBA8888) - private fun fileToAtlantes(matte: FileHandle, glow: FileHandle?) { + private fun fileToAtlantes(modname: String, matte: FileHandle, glow: FileHandle?) { val tilesPixmap = Pixmap(matte) val tilesGlowPixmap = if (glow != null) Pixmap(glow) else nullTile - val blockID = matte.nameWithoutExtension().toInt() + val blockName = matte.nameWithoutExtension().toInt() // basically a filename + val blockID = "$modname:$blockName" // determine the type of the block (populate tags list) // predefined by the image dimension: 16x16 for (1,0) @@ -297,7 +244,7 @@ object CreateTileAtlas { // 112x112 or 224x224 else { if (tilesPixmap.width != tilesPixmap.height && tilesPixmap.width % (7 * TILE_SIZE) >= 2) { - throw IllegalArgumentException("Unrecognized image dimension: ${tilesPixmap.width}x${tilesPixmap.height}") + throw IllegalArgumentException("Unrecognized image dimension ${tilesPixmap.width}x${tilesPixmap.height} from $modname:${matte.name()}") } // figure out the tags var connectionType = 0 @@ -317,19 +264,29 @@ object CreateTileAtlas { drawToAtlantes(tilesPixmap, tilesGlowPixmap, tileCount) } + itemSheetNumbers[blockID] = itemSheetCursor + itemSheetCursor += 1 + tilesPixmap.dispose() } + fun tileIDtoAtlasNumber(tileID: ItemID) = tags[tileID]?.tileNumber + ?: throw NullPointerException("AtlasNumbers mapping from $tileID does not exist") + fun tileIDtoItemSheetNumber(tileID: ItemID) = itemSheetNumbers[tileID] + ?: throw NullPointerException("ItemSheetNumber mapping from $tileID does not exist") + /** * This function must precede the drawToAtlantes() function, as the marking requires the variable * 'atlasCursor' and the draw function modifies it! */ - private fun addTag(id: Int, connectionType: Int, maskType: Int) { + private fun addTag(id: ItemID, connectionType: Int, maskType: Int) { if (tags.containsKey(id)) { throw Error("Block $id already exists") } tags[id] = RenderTag(atlasCursor, connectionType, maskType) + + printdbg(this, "tileName ${id} ->> tileNumber ${atlasCursor}") } private fun drawToAtlantes(pixmap: Pixmap, glow: Pixmap, tilesCount: Int) { @@ -391,6 +348,9 @@ object CreateTileAtlas { } } + /** + * @param tileNumber ordinal number of a tile in the texture atlas + */ data class RenderTag(val tileNumber: Int, val connectionType: Int, val maskType: Int) { companion object { const val CONNECT_MUTUAL = 0 @@ -422,6 +382,8 @@ object CreateTileAtlas { atlasSpring.dispose() atlasFluid.dispose() atlasGlow.dispose() + //itemTerrainTexture.dispose() //BlocksDrawer will dispose of it as it disposes of 'tileItemTerrain (TextureRegionPack)' + //itemWallTexture.dispose() //BlocksDrawer will dispose of it as it disposes of 'tileItemWall (TextureRegionPack)' nullTile.dispose() } diff --git a/src/net/torvald/terrarum/worlddrawer/FeaturesDrawer.kt b/src/net/torvald/terrarum/worlddrawer/FeaturesDrawer.kt index ae89b3661..819ddee0e 100644 --- a/src/net/torvald/terrarum/worlddrawer/FeaturesDrawer.kt +++ b/src/net/torvald/terrarum/worlddrawer/FeaturesDrawer.kt @@ -27,13 +27,13 @@ object FeaturesDrawer { var colTemp: Int = 0 private set - private val TILES_COLD = intArrayOf( + private val TILES_COLD = arrayOf( Block.ICE_MAGICAL , Block.ICE_FRAGILE , Block.ICE_NATURAL , Block.SNOW) - private val TILES_WARM = intArrayOf( + private val TILES_WARM = arrayOf( Block.SAND_DESERT , Block.SAND_RED) diff --git a/src/net/torvald/terrarum/worlddrawer/LightCalculatorContext.kt b/src/net/torvald/terrarum/worlddrawer/LightCalculatorContext.kt index 7064a2f96..ecb74c57a 100644 --- a/src/net/torvald/terrarum/worlddrawer/LightCalculatorContext.kt +++ b/src/net/torvald/terrarum/worlddrawer/LightCalculatorContext.kt @@ -20,135 +20,5 @@ internal class LightCalculatorContext( private val lightmap: UnsafeCvecArray, private val lanternMap: HashMap ) { - - private val colourNull = Cvec(0) - - private val ambientAccumulator = Cvec(0f,0f,0f,0f) - private val lightLevelThis = Cvec(0) - private val fluidAmountToCol = Cvec(0) - private val thisTileLuminosity = Cvec(0) - private val thisTileOpacity = Cvec(0) - private val thisTileOpacity2 = Cvec(0) // thisTileOpacity * sqrt(2) - private val sunLight = Cvec(0) - private var thisFluid = GameWorld.FluidInfo(Fluid.NULL, 0f) - private var thisTerrain = 0 - private var thisWall = 0 - - private fun getLightsAndShades(x: Int, y: Int) { - val (x, y) = world.coerceXY(x, y) - - lightLevelThis.set(colourNull) - thisTerrain = world.getTileFromTerrainRaw(x, y) - thisFluid = world.getFluid(x, y) - thisWall = world.getTileFromWallRaw(x, y) - - // regarding the issue #26 - // uncomment this if you're facing diabolically indescribable bugs - /*try { - val fuck = BlockCodex[thisTerrain].getLumCol(x, y) - } - catch (e: NullPointerException) { - System.err.println("## NPE -- x: $x, y: $y, value: ${thisTerrain}") - e.printStackTrace() - // create shitty minidump - System.err.println("MINIMINIDUMP START") - for (xx in x - 16 until x + 16) { - val raw = world.getTileFromTerrain(xx, y) - val lsb = raw.and(0xff).toString(16).padStart(2, '0') - val msb = raw.ushr(8).and(0xff).toString(16).padStart(2, '0') - System.err.print(lsb) - System.err.print(msb) - System.err.print(" ") - } - System.err.println("\nMINIMINIDUMP END") - - exitProcess(1) - }*/ - - if (thisFluid.type != Fluid.NULL) { - fluidAmountToCol.set(thisFluid.amount, thisFluid.amount, thisFluid.amount, thisFluid.amount) - - thisTileLuminosity.set(BlockCodex[thisTerrain].getLumCol(x, y)) - thisTileLuminosity.maxAndAssign(BlockCodex[thisFluid.type].getLumCol(x, y).mul(fluidAmountToCol)) // already been div by four - thisTileOpacity.set(BlockCodex[thisTerrain].opacity) - thisTileOpacity.maxAndAssign(BlockCodex[thisFluid.type].opacity.mul(fluidAmountToCol)) // already been div by four - } - else { - thisTileLuminosity.set(BlockCodex[thisTerrain].getLumCol(x, y)) - thisTileOpacity.set(BlockCodex[thisTerrain].opacity) - } - - thisTileOpacity2.set(thisTileOpacity); thisTileOpacity2.mul(1.41421356f) - //sunLight.set(world.globalLight); sunLight.mul(DIV_FLOAT) // moved to fireRecalculateEvent() - - - // open air || luminous tile backed by sunlight - if ((thisTerrain == AIR && thisWall == AIR) || (thisTileLuminosity.nonZero() && thisWall == AIR)) { - lightLevelThis.set(sunLight) - } - - // blend lantern - lightLevelThis.maxAndAssign(thisTileLuminosity).maxAndAssign(lanternMap[LandUtil.getBlockAddr(world, x, y)] ?: colourNull) - } - - fun calculateAndAssign(worldX: Int, worldY: Int) { - - //if (inNoopMask(worldX, worldY)) return - - // O(9n) == O(n) where n is a size of the map - - getLightsAndShades(worldX, worldY) - - val x = worldX.convX() - val y = worldY.convY() - - // calculate ambient - /* + * + 0 4 1 - * * @ * 6 @ 7 - * + * + 2 5 3 - * sample ambient for eight points and apply attenuation for those - * maxblend eight values and use it - */ - - // will "overwrite" what's there in the lightmap if it's the first pass - // takes about 2 ms on 6700K - /* + */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x - 1, y - 1, thisTileOpacity2)) - /* + */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x + 1, y - 1, thisTileOpacity2)) - /* + */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x - 1, y + 1, thisTileOpacity2)) - /* + */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x + 1, y + 1, thisTileOpacity2)) - /* * */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x, y - 1, thisTileOpacity)) - /* * */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x, y + 1, thisTileOpacity)) - /* * */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x - 1, y, thisTileOpacity)) - /* * */lightLevelThis.maxAndAssign(LightmapRenderer.darkenColoured(x + 1, y, thisTileOpacity)) - - - //return lightLevelThis.cpy() // it HAS to be a cpy(), otherwise all cells gets the same instance - //setLightOf(lightmap, x, y, lightLevelThis.cpy()) - - lightmap.setR(x, y, lightLevelThis.r) - lightmap.setG(x, y, lightLevelThis.g) - lightmap.setB(x, y, lightLevelThis.b) - lightmap.setA(x, y, lightLevelThis.a) - } - - private fun Cvec.maxAndAssign(other: Cvec): Cvec { - // TODO investigate: if I use assignment instead of set(), it blackens like the vector branch. --Torvald, 2019-06-07 - // that was because you forgot 'this.r/g/b/a = ' part, bitch. --Torvald, 2019-06-07 - this.r = if (this.r > other.r) this.r else other.r - this.g = if (this.g > other.g) this.g else other.g - this.b = if (this.b > other.b) this.b else other.b - this.a = if (this.a > other.a) this.a else other.a - - return this - } - - private fun Cvec.nonZero() = this.r.abs() > LightmapRenderer.epsilon || - this.g.abs() > LightmapRenderer.epsilon || - this.b.abs() > LightmapRenderer.epsilon || - this.a.abs() > LightmapRenderer.epsilon - - /** World coord to array coord */ - private inline fun Int.convX() = this - LightmapRenderer.for_x_start + LightmapRenderer.overscan_open - /** World coord to array coord */ - private inline fun Int.convY() = this - LightmapRenderer.for_y_start + LightmapRenderer.overscan_open + // No longer in use because of the much efficient light updating method } \ No newline at end of file diff --git a/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt b/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt index 63628f63b..4ed4a5625 100644 --- a/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt +++ b/src/net/torvald/terrarum/worlddrawer/LightmapRendererNew.kt @@ -487,14 +487,14 @@ object LightmapRenderer { if (_thisFluid.type != Fluid.NULL) { _fluidAmountToCol.set(_thisFluid.amount, _thisFluid.amount, _thisFluid.amount, _thisFluid.amount) - _thisTileLuminosity.set(BlockCodex[_thisTerrain].getLumCol(worldX, worldY)) + _thisTileLuminosity.set(BlockCodex[world.tileNumberToNameMap[_thisTerrain]].getLumCol(worldX, worldY)) _thisTileLuminosity.maxAndAssign(BlockCodex[_thisFluid.type].getLumCol(worldX, worldY).mul(_fluidAmountToCol)) // already been div by four - _mapThisTileOpacity.setVec(lx, ly, BlockCodex[_thisTerrain].opacity) + _mapThisTileOpacity.setVec(lx, ly, BlockCodex[world.tileNumberToNameMap[_thisTerrain]].opacity) _mapThisTileOpacity.max(lx, ly, BlockCodex[_thisFluid.type].opacity.mul(_fluidAmountToCol))// already been div by four } else { - _thisTileLuminosity.set(BlockCodex[_thisTerrain].getLumCol(worldX, worldY)) - _mapThisTileOpacity.setVec(lx, ly, BlockCodex[_thisTerrain].opacity) + _thisTileLuminosity.set(BlockCodex[world.tileNumberToNameMap[_thisTerrain]].getLumCol(worldX, worldY)) + _mapThisTileOpacity.setVec(lx, ly, BlockCodex[world.tileNumberToNameMap[_thisTerrain]].opacity) } _mapThisTileOpacity2.setR(lx, ly, _mapThisTileOpacity.getR(lx, ly) * 1.41421356f) @@ -504,7 +504,8 @@ object LightmapRenderer { // open air || luminous tile backed by sunlight - if ((_thisTerrain == AIR && _thisWall == AIR) || (_thisTileLuminosity.nonZero() && _thisWall == AIR)) { + if ((world.tileNumberToNameMap[_thisTerrain] == AIR && world.tileNumberToNameMap[_thisWall] == AIR) || + (_thisTileLuminosity.nonZero() && world.tileNumberToNameMap[_thisWall] == AIR)) { _mapLightLevelThis.setVec(lx, ly, sunLight) } diff --git a/work_files/DataFormats/Savegame container.txt b/work_files/DataFormats/Savegame container.txt index 85bd10594..a7bbdf1b6 100644 --- a/work_files/DataFormats/Savegame container.txt +++ b/work_files/DataFormats/Savegame container.txt @@ -14,9 +14,9 @@ Files contained the TerranVirtualDisk is as follows: Has fixed Entry ID of 32763 world[n] -- Layer Data (TEMD); [n] is a serial number of the world (starts at 1) Has fixed Entry ID of [n] - (any random number in Hex ACTORID_MIN..FFFFFFFF) -- Serialised Entity Information (including Player) - (PLAYER_REF_ID in Hex -- 91A7E2) -- Player Character Information (Serialised--JSON'd--Entity Information) - (51621D) -- The Debug Player (Serialised Entity Information) + (any random number in Hex ACTORID_MIN..FFFFFFFF) -- Serialised Entity Information (including Player), Entry ID is random + (PLAYER_REF_ID in Hex -- 91A7E2) -- Player Character Information (Serialised--JSON'd--Entity Information), Entry ID is random + (51621D) -- The Debug Player (Serialised Entity Information), Entry ID is random load_order.txt -- LoadOrder.csv (NOT zipped) Has fixed Entry ID of 32767 diff --git a/work_files/DataFormats/Worldmap format.txt b/work_files/DataFormats/Worldmap format.txt index 0e3265f2a..ff70323af 100644 --- a/work_files/DataFormats/Worldmap format.txt +++ b/work_files/DataFormats/Worldmap format.txt @@ -43,17 +43,17 @@ Ord Hex Description # A payload is consisted as follows: # # Literal Description -# "\0pLd" Payload header [00, 70, 4C, 64] +# "\0pLd" Payload header [00, 70, 4C, 64] # [4] Identifier. 4 lettres ASCII string # [6] Uncompressed size of DEFLATEd binary (max size 256 TB) +# [6] Length of the actual payload (max size 256 TB) # [..] DEFLATEd binary (begins with one of these: 0x789C, 0x78DA, 0x7801) -# "EndPYLd\xFF" Payload footer [45, 6E, 64, 50, 59, 4C, 64, FF] Payload "TERR" -- world terrain data in Uint16 Uncompressed size will be 2x of (width * height) -Payload "WALL" -- world walls data in Unit16 +Payload "WALL" -- world walls data in Uint16 Uncompressed size will be 2x of (width * height) Payload "TdMG" -- world terrain damage data, array of: (Int48 tileAddress, Float32 damage) @@ -71,11 +71,17 @@ Payload "FlFL" -- world fluid fills, array of: (Int48 tileAddress, Float32 amoun Payload "WiNt" -- wiring nodes, in JSON format -Payload "CtYP" -- conduit types, array of: (Int48 tileAddress, Uint32 bitarray) +Payload "TMaP" -- tile number to name map, array of: (Int32, tileNumber, String itemID) + String is null-terminated byte array + +TODO need a format that can store arbitrary number of conduits, not just limited to 32 + +/*Payload "CtYP" -- conduit types, array of: (Int48 tileAddress, Uint32 bitarray) can hold 32 different wires simultaneously Payload "CfL0" -- conduit fills, aka size of liquid/gas packet, array of: (Int48 tileAddress, Float32 fill) - CfL0..CfL9, CfLa..CfLf are available to store values for 16 different things. + CfL0..CfL9, CfLa..CfLf are available to store values for 16 different things.*/ + EOF 45 E EOF 6E n @@ -86,7 +92,3 @@ EOF 4D M EOF FF Byte order mark EOF FE Byte order mark - -* To read layers: you'll need to search for specific strings, namely ["TERR", "WALL", "WIRE"] -* It is possible that compressed data happen to replicate any of the internal identifiers - (e.g. "\0pLdTERR", "EndTEM\xFF\xFE", "EndPYLd\xFF"), but such probability is very low (0.000000000000000005421 %) diff --git a/work_files/graphics/terrain/wires_collection_signalwires.kra b/work_files/graphics/terrain/wires_collection_signalwires.kra index 0d8f3d8bb..af78d2574 100644 --- a/work_files/graphics/terrain/wires_collection_signalwires.kra +++ b/work_files/graphics/terrain/wires_collection_signalwires.kra @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:706477e99158af16a12a87ba488da59ecf0f91bc3d6ff6ef5f961e7bbe089763 -size 302571 +oid sha256:ee5bc50078b62fd904150e0cdcec4ed9b3ec1f5509ebda1c836cb171049a6dc4 +size 302514