From 81f0499c9dc754a5f946136a2ca381178c5d4a5a Mon Sep 17 00:00:00 2001 From: minjaesong Date: Thu, 20 Jul 2017 00:36:41 +0900 Subject: [PATCH] limitedly successful attempt to create a title screen --- assets/modules/basegame/blocks/blocks.csv | 6 +- src/net/torvald/terrarum/Ingame.kt | 109 ++---- src/net/torvald/terrarum/LoadScreen.kt | 68 +++- src/net/torvald/terrarum/Terrarum.kt | 51 ++- src/net/torvald/terrarum/TitleScreen.kt | 363 ++++++++++++++++++ .../terrarum/blockproperties/BlockPropUtil.kt | 4 +- .../torvald/terrarum/console/CommandDict.kt | 6 +- src/net/torvald/terrarum/console/EchoError.kt | 3 +- .../terrarum/console/ExportLayerData.kt | 26 ++ .../terrarum/console/ImportLayerData.kt | 33 ++ .../gameactors/PlayerBuilderSigrid.kt | 2 +- .../torvald/terrarum/gameworld/GameWorld.kt | 19 +- .../torvald/terrarum/gameworld/MapLayer.kt | 12 +- .../terrarum/gameworld/PairedMapLayer.kt | 20 +- .../terrarum/serialise/ReadGameMapData.kt | 42 -- .../terrarum/serialise/ReadLayerData.kt | 114 ++++++ .../torvald/terrarum/serialise/WriteCSV.kt | 2 +- .../terrarum/serialise/WriteGameMapData.kt | 75 ---- .../terrarum/serialise/WriteLayerData.kt | 126 ++++++ src/net/torvald/terrarum/ui/UICanvas.kt | 2 + src/net/torvald/terrarum/ui/UIHandler.kt | 16 +- src/net/torvald/terrarum/ui/UIInventory.kt | 100 ++--- src/net/torvald/terrarum/ui/UIItem.kt | 28 ++ .../terrarum/ui/UIItemTextButtonList.kt | 41 +- src/net/torvald/terrarum/ui/UIStartMenu.kt | 107 ++++++ .../torvald/terrarum/weather/WeatherMixer.kt | 38 +- .../terrarum/worlddrawer/BlocksDrawer_old.kt | 4 +- .../terrarum/worlddrawer/FeaturesDrawer.kt | 8 +- .../terrarum/worlddrawer/LightmapRenderer.kt | 52 +-- .../terrarum/worlddrawer/WorldCamera.kt | 24 +- .../worldgenerator/FloatingIslandsPreset.kt | 1 + .../terrarum/worldgenerator/WorldGenerator.kt | 60 +-- work_files/DataFormats/Map data format.txt | 14 +- work_files/GameDesign/WORLD_UNIVERSE_LORE.md | 2 + 34 files changed, 1168 insertions(+), 410 deletions(-) create mode 100644 src/net/torvald/terrarum/TitleScreen.kt create mode 100644 src/net/torvald/terrarum/console/ExportLayerData.kt create mode 100644 src/net/torvald/terrarum/console/ImportLayerData.kt delete mode 100644 src/net/torvald/terrarum/serialise/ReadGameMapData.kt create mode 100644 src/net/torvald/terrarum/serialise/ReadLayerData.kt delete mode 100644 src/net/torvald/terrarum/serialise/WriteGameMapData.kt create mode 100644 src/net/torvald/terrarum/serialise/WriteLayerData.kt create mode 100644 src/net/torvald/terrarum/ui/UIStartMenu.kt diff --git a/assets/modules/basegame/blocks/blocks.csv b/assets/modules/basegame/blocks/blocks.csv index 1f368cca5..92f15eaac 100644 --- a/assets/modules/basegame/blocks/blocks.csv +++ b/assets/modules/basegame/blocks/blocks.csv @@ -63,7 +63,7 @@ "212"; "212";"BLOCK_ILLUMINATOR_FUCHSIA" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.9188";"0.0000";"0.7156";"0.0000"; "0"; "0"; "N/A"; "0";"16" "213"; "213";"BLOCK_ILLUMINATOR_PURPLE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.7156";"0.0000";"0.9188";"0.0000"; "0"; "0"; "N/A"; "0";"16" "214"; "214";"BLOCK_ILLUMINATOR_BLUE" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.1996";"0.9188";"0.0000"; "0"; "0"; "N/A"; "0";"16" - "215"; "215";"BLOCK_ILLUMINATOR_CYAN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.0000";"0.8368";"0.9188";"0.0000"; "0"; "0"; "N/A"; "0";"16" + "215"; "215";"BLOCK_ILLUMINATOR_CYAN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.4621";"1.4188";"1.2368";"0.0000"; "0"; "0"; "N/A"; "0";"16" "216"; "216";"BLOCK_ILLUMINATOR_GREEN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.2112";"1.0000";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16" "217"; "217";"BLOCK_ILLUMINATOR_GREEN_DARK";"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.1252";"0.4068";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16" "218"; "218";"BLOCK_ILLUMINATOR_BROWN" ;"0.0312";"0.0312";"0.0312";"0.0312"; "1"; "N/A";"glas"; "0"; "1"; "0"; "1";"0.3324";"0.1252";"0.0000";"0.0000"; "0"; "0"; "N/A"; "0";"16" @@ -164,6 +164,10 @@ # Sunstone: Artificial sunlight, change colour over time in sync with sunlight. The light is set by game's code. # Sunlight capacitor: daylight at noon. Set by game's code. +# BLOCK_ILLUMINATOR_CYAN is actually a SUPER_LUMINATOR, cyan colour is used as: +# 1. It has quite a brightness on RGB colour space +# 2. Helmholz-Kohlraush effect + ## Tiles ## diff --git a/src/net/torvald/terrarum/Ingame.kt b/src/net/torvald/terrarum/Ingame.kt index 1bd5d73a9..80f6ea6f8 100644 --- a/src/net/torvald/terrarum/Ingame.kt +++ b/src/net/torvald/terrarum/Ingame.kt @@ -76,6 +76,14 @@ class Ingame(val batch: SpriteBatch) : Screen { companion object { val lightmapDownsample = 2f //2f: still has choppy look when the camera moves but unnoticeable when blurred + + + /** Sets camera position so that (0,0) would be top-left of the screen, (width, height) be bottom-right. */ + fun setCameraPosition(batch: SpriteBatch, camera: Camera, newX: Float, newY: Float) { + camera.position.set((-newX + Terrarum.HALFW).round(), (-newY + Terrarum.HALFH).round(), 0f) + camera.update() + batch.projectionMatrix = camera.combined + } } @@ -156,23 +164,6 @@ class Ingame(val batch: SpriteBatch) : Screen { var camera = OrthographicCamera(Terrarum.WIDTH.toFloat(), Terrarum.HEIGHT.toFloat()) - /** Actually just a mesh of four vertices, two triangles -- not a literal glQuad */ - var fullscreenQuad = Mesh( - true, 4, 6, - VertexAttribute.Position(), - VertexAttribute.ColorUnpacked(), - VertexAttribute.TexCoords(0) - ) - - init { - fullscreenQuad.setVertices(floatArrayOf( - 0f, 0f, 0f, 1f, 1f, 1f, 1f, 0f, 1f, - Terrarum.WIDTH.toFloat(), 0f, 0f, 1f, 1f, 1f, 1f, 1f, 1f, - Terrarum.WIDTH.toFloat(), Terrarum.HEIGHT.toFloat(), 0f, 1f, 1f, 1f, 1f, 1f, 0f, - 0f, Terrarum.HEIGHT.toFloat(), 0f, 1f, 1f, 1f, 1f, 0f, 0f - )) - fullscreenQuad.setIndices(shortArrayOf(0, 1, 2, 2, 3, 0)) - } // invert Y fun initViewPort(width: Int, height: Int) { @@ -200,13 +191,18 @@ class Ingame(val batch: SpriteBatch) : Screen { override fun show() { //initViewPort(Terrarum.WIDTH, Terrarum.HEIGHT) - // gameLoadMode and gameLoadInfoPayload must be set beforehand!! when (gameLoadMode) { GameLoadMode.CREATE_NEW -> enter(gameLoadInfoPayload as NewWorldParameters) GameLoadMode.LOAD_FROM -> enter(gameLoadInfoPayload as GameSaveData) } + + LightmapRenderer.world = this.world + //BlocksDrawer.world = this.world + FeaturesDrawer.world = this.world + + gameInitialised = true } data class GameSaveData( @@ -236,13 +232,11 @@ class Ingame(val batch: SpriteBatch) : Screen { world = gameSaveData.world historicalFigureIDBucket = gameSaveData.historicalFigureIDBucket playableActorDelegate = PlayableActorDelegate(gameSaveData.realGamePlayer) - addNewActor(player!!) + addNewActor(player) //initGame() - - gameInitialised = true } } @@ -284,12 +278,15 @@ class Ingame(val batch: SpriteBatch) : Screen { //initGame() - - gameInitialised = true } } - fun initGame() { + /** Load rest of the game with GL context */ + fun postInit() { + //LightmapRenderer.world = this.world + BlocksDrawer.world = this.world + //FeaturesDrawer.world = this.world + Gdx.input.inputProcessor = GameController @@ -415,27 +412,16 @@ class Ingame(val batch: SpriteBatch) : Screen { if (gameLoadMode == GameLoadMode.CREATE_NEW) { playableActorDelegate = PlayableActorDelegate(PlayerBuilderSigrid()) - // determine spawn position - val spawnX = world.width / 2 - var solidTileCounter = 0 - while (true) { - if (BlockCodex[world.getTileFromTerrain(spawnX, solidTileCounter)].isSolid || - BlockCodex[world.getTileFromTerrain(spawnX - 1, solidTileCounter)].isSolid || - BlockCodex[world.getTileFromTerrain(spawnX + 1, solidTileCounter)].isSolid - ) break - - solidTileCounter += 1 - } - + // go to spawn position player.setPosition( - spawnX * FeaturesDrawer.TILE_SIZE.toDouble(), - solidTileCounter * FeaturesDrawer.TILE_SIZE.toDouble() + world.spawnX * FeaturesDrawer.TILE_SIZE.toDouble(), + world.spawnY * FeaturesDrawer.TILE_SIZE.toDouble() ) addNewActor(player) } - initGame() + postInit() gameFullyLoaded = true @@ -496,7 +482,7 @@ class Ingame(val batch: SpriteBatch) : Screen { BlockPropUtil.dynamicLumFuncTickClock() world.updateWorldTime(delta) //WorldSimulator(player, delta) - WeatherMixer.update(delta) + WeatherMixer.update(delta, player) BlockStats.update() if (!(CommandDict["setgl"] as SetGlobalLightOverride).lightOverride) world.globalLight = WeatherMixer.globalLightNow @@ -506,7 +492,7 @@ class Ingame(val batch: SpriteBatch) : Screen { // camera-related updates // //////////////////////////// FeaturesDrawer.update(delta) - WorldCamera.update() + WorldCamera.update(world, player) @@ -555,7 +541,6 @@ class Ingame(val batch: SpriteBatch) : Screen { // Post-update; ones that needs everything is completed // - FeaturesDrawer.render(batch) // // update lightmap on every other frames, OR full-frame if the option is true if (Terrarum.getConfigBoolean("fullframelightupdate") or (Terrarum.GLOBAL_RENDER_TIMER % 2 == 1)) { // LightmapRenderer.fireRecalculateEvent() // @@ -579,7 +564,7 @@ class Ingame(val batch: SpriteBatch) : Screen { /////////////////////////// // draw world to the FBO // /////////////////////////// - processBlur(LightmapRenderer.DRAW_FOR_RGB) + processBlur(lightmapFboA, lightmapFboB, LightmapRenderer.DRAW_FOR_RGB) worldDrawFrameBuffer.inAction(camera, batch) { batch.inUse { @@ -658,7 +643,7 @@ class Ingame(val batch: SpriteBatch) : Screen { ////////////////////////// // draw glow to the FBO // ////////////////////////// - processBlur(LightmapRenderer.DRAW_FOR_ALPHA) + processBlur(lightmapFboA, lightmapFboB, LightmapRenderer.DRAW_FOR_ALPHA) worldGlowFrameBuffer.inAction(camera, batch) { batch.inUse { @@ -736,7 +721,7 @@ class Ingame(val batch: SpriteBatch) : Screen { Terrarum.shaderBlendGlow.setUniformMatrix("u_projTrans", camera.combined) Terrarum.shaderBlendGlow.setUniformi("u_texture", 0) Terrarum.shaderBlendGlow.setUniformi("tex1", 1) - fullscreenQuad.render(Terrarum.shaderBlendGlow, GL20.GL_TRIANGLES) + Terrarum.fullscreenQuad.render(Terrarum.shaderBlendGlow, GL20.GL_TRIANGLES) Terrarum.shaderBlendGlow.end() @@ -767,7 +752,7 @@ class Ingame(val batch: SpriteBatch) : Screen { // draw skybox to screen // /////////////////////////// - WeatherMixer.render(camera) + WeatherMixer.render(camera, world) @@ -857,12 +842,12 @@ class Ingame(val batch: SpriteBatch) : Screen { ///////////////////////////// // draw some overlays (UI) // ///////////////////////////// - uiContainer.forEach { if (it != consoleHandler) it.render(batch) } + uiContainer.forEach { if (it != consoleHandler) it.render(batch, camera) } - debugWindow.render(batch) + debugWindow.render(batch, camera) // make sure console draws on top of other UIs - consoleHandler.render(batch) - notifier.render(batch) + consoleHandler.render(batch, camera) + notifier.render(batch, camera) blendNormal() @@ -1030,7 +1015,7 @@ class Ingame(val batch: SpriteBatch) : Screen { gwin.drawLine(0f, Terrarum.HEIGHT / 2f, Terrarum.WIDTH.toFloat(), Terrarum.HEIGHT / 2f)*/ } - private fun processBlur(mode: Int) { + fun processBlur(lightmapFboA: FrameBuffer, lightmapFboB: FrameBuffer, mode: Int) { val blurIterations = 5 // ideally, 4 * radius; must be even/odd number -- odd/even number will flip the image val blurRadius = 4f / lightmapDownsample // (5, 4f); using low numbers for pixel-y aesthetics @@ -1530,6 +1515,7 @@ class Ingame(val batch: SpriteBatch) : Screen { * @see net.torvald.terrarum.Terrarum */ override fun resize(width: Int, height: Int) { + worldDrawFrameBuffer.dispose() worldDrawFrameBuffer = FrameBuffer(worldFBOformat, Terrarum.WIDTH, Terrarum.HEIGHT, false) worldGlowFrameBuffer.dispose() @@ -1547,23 +1533,6 @@ class Ingame(val batch: SpriteBatch) : Screen { - // re-calculate fullscreen quad - fullscreenQuad = Mesh( - true, 4, 6, - VertexAttribute.Position(), - VertexAttribute.ColorUnpacked(), - VertexAttribute.TexCoords(0) - ) - fullscreenQuad.setVertices(floatArrayOf( - 0f, 0f, 0f, 1f, 1f, 1f, 1f, 0f, 1f, - Terrarum.WIDTH.toFloat(), 0f, 0f, 1f, 1f, 1f, 1f, 1f, 1f, - Terrarum.WIDTH.toFloat(), Terrarum.HEIGHT.toFloat(), 0f, 1f, 1f, 1f, 1f, 1f, 0f, - 0f, Terrarum.HEIGHT.toFloat(), 0f, 1f, 1f, 1f, 1f, 0f, 0f - )) - fullscreenQuad.setIndices(shortArrayOf(0, 1, 2, 2, 3, 0)) - - - if (gameInitialised) { LightmapRenderer.fireRecalculateEvent() } @@ -1614,8 +1583,6 @@ class Ingame(val batch: SpriteBatch) : Screen { * Camera will be moved so that (newX, newY) would be sit on the top-left edge. */ fun setCameraPosition(newX: Float, newY: Float) { - camera.position.set((-newX + Terrarum.HALFW).round(), (-newY + Terrarum.HALFH).round(), 0f) - camera.update() - batch.projectionMatrix = camera.combined + Ingame.setCameraPosition(batch, camera, newX, newY) } } diff --git a/src/net/torvald/terrarum/LoadScreen.kt b/src/net/torvald/terrarum/LoadScreen.kt index c66d229a6..37777a1b8 100644 --- a/src/net/torvald/terrarum/LoadScreen.kt +++ b/src/net/torvald/terrarum/LoadScreen.kt @@ -59,6 +59,8 @@ object LoadScreen : ScreenAdapter() { } + private var errorTrapped = false + override fun show() { messages.clear() @@ -72,7 +74,16 @@ object LoadScreen : ScreenAdapter() { else { val runnable = object : Runnable { override fun run() { - screenToLoad!!.show() + try { + screenToLoad!!.show() + } + catch (e: Exception) { + addMessage("$ccR$e") + errorTrapped = true + + System.err.println("Error while loading:") + e.printStackTrace() + } } } screenLoadingThread = Thread(runnable, "LoadScreen GameLoader") @@ -85,7 +96,10 @@ object LoadScreen : ScreenAdapter() { textFbo = FrameBuffer( Pixmap.Format.RGBA4444, - Terrarum.fontGame.getWidth(Lang["MENU_IO_LOADING"]), + maxOf( + Terrarum.fontGame.getWidth(Lang["MENU_IO_LOADING"]), + Terrarum.fontGame.getWidth(Lang["ERROR_GENERIC_TEXT"]) + ), Terrarum.fontGame.lineHeight.toInt(), true ) @@ -97,7 +111,7 @@ object LoadScreen : ScreenAdapter() { } - val textX: Float; get() = (Terrarum.WIDTH * 0.75f).floor() + val textX: Float; get() = (Terrarum.WIDTH * 0.72f).floor() private var genuineSonic = false // the "NOW LOADING..." won't appear unless the arrow first run passes it (it's totally not a GenuineIntel tho) private var doContextChange = false @@ -119,36 +133,50 @@ object LoadScreen : ScreenAdapter() { Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) } - glideTimer += delta - // reset timer - if (glideTimer >= arrowObjGlideSize / arrowGlideSpeed) { - glideTimer -= arrowObjGlideSize / arrowGlideSpeed + // update arrow object + if (!errorTrapped) { + glideTimer += delta + // reset timer + if (glideTimer >= arrowObjGlideSize / arrowGlideSpeed) { + glideTimer -= arrowObjGlideSize / arrowGlideSpeed - // change screen WHEN the timer is reset. - // In other words, the arrow must hit the goal BEFORE context change take place - if (screenToLoad?.gameInitialised ?: false) { - doContextChange = true + // change screen WHEN the timer is reset. + // In other words, the arrow must hit the goal BEFORE context change take place + if (screenToLoad?.gameInitialised ?: false) { + doContextChange = true + } } + arrowObjPos = glideTimer * arrowGlideSpeed + } + else { + genuineSonic = true + arrowObjPos = 0f } - arrowObjPos = glideTimer * arrowGlideSpeed + val textToPrint = if (errorTrapped) Lang["ERROR_GENERIC_TEXT"] else Lang["MENU_IO_LOADING"] + val textWidth = Terrarum.fontGame.getWidth(textToPrint).toFloat() + if (!doContextChange) { // draw text to FBO textFbo.inAction(camera, Terrarum.batch) { Terrarum.batch.inUse { + + blendNormal() Terrarum.fontGame it.color = Color.WHITE - Terrarum.fontGame.draw(it, Lang["MENU_IO_LOADING"], 0.33f, 0f) // x 0.5? I dunno but it breaks w/o it + + + Terrarum.fontGame.draw(it, textToPrint, (textFbo.width - textWidth) / 2f + 0.33f, 0f) // x 0.33? I dunno but it breaks w/o it blendMul() - // draw flipped + // draw colour overlay, flipped it.draw(textOverlayTex, - 0f, + (textFbo.width - textWidth) / 2f, Terrarum.fontGame.lineHeight, - textOverlayTex.width.toFloat(), + textWidth, -Terrarum.fontGame.lineHeight ) } @@ -186,9 +214,11 @@ object LoadScreen : ScreenAdapter() { // draw coloured arrows - arrowColours.forEachIndexed { index, color -> - it.color = color - it.draw(arrowObjTex, arrowObjPos + arrowObjGlideOffsetX + arrowObjTex.width * index, glideDispY) + if (!errorTrapped) { + arrowColours.forEachIndexed { index, color -> + it.color = color + it.draw(arrowObjTex, arrowObjPos + arrowObjGlideOffsetX + arrowObjTex.width * index, glideDispY) + } } diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index 63bc3f538..f27c58c49 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -36,6 +36,7 @@ import java.util.* */ const val GAME_NAME = "Terrarum" +const val COPYRIGHT_DATE_NAME = "Copyright 2013-2017 Torvald (minjaesong)" fun main(args: Array) { Terrarum // invoke @@ -258,6 +259,11 @@ object Terrarum : Game() { lateinit var textureWhiteSquare: Texture + /** Actually just a mesh of four vertices, two triangles -- not a literal glQuad */ + lateinit var fullscreenQuad: Mesh; private set + + + init { println("$NAME version $VERSION_STRING") @@ -314,6 +320,25 @@ object Terrarum : Game() { override fun create() { + fullscreenQuad = Mesh( + true, 4, 6, + VertexAttribute.Position(), + VertexAttribute.ColorUnpacked(), + VertexAttribute.TexCoords(0) + ) + + fullscreenQuad.setVertices(floatArrayOf( + 0f, 0f, 0f, 1f, 1f, 1f, 1f, 0f, 1f, + Terrarum.WIDTH.toFloat(), 0f, 0f, 1f, 1f, 1f, 1f, 1f, 1f, + Terrarum.WIDTH.toFloat(), Terrarum.HEIGHT.toFloat(), 0f, 1f, 1f, 1f, 1f, 1f, 0f, + 0f, Terrarum.HEIGHT.toFloat(), 0f, 1f, 1f, 1f, 1f, 0f, 0f + )) + fullscreenQuad.setIndices(shortArrayOf(0, 1, 2, 2, 3, 0)) + + + + + TextureRegionPack.globalFlipY = true // !! TO MAKE LEGACY CODE RENDER ON ITS POSITION !! Gdx.graphics.isContinuousRendering = true @@ -375,13 +400,18 @@ object Terrarum : Game() { - ingame = Ingame(batch) - ingame!!.gameLoadInfoPayload = Ingame.NewWorldParameters(8192, 2048, HQRNG().nextLong()) - ingame!!.gameLoadMode = Ingame.GameLoadMode.CREATE_NEW + //ingame = Ingame(batch) + //ingame!!.gameLoadInfoPayload = Ingame.NewWorldParameters(8192, 2048, HQRNG().nextLong()) + + // TODO: create world being used by title screen, and serialise it. + //ingame!!.gameLoadInfoPayload = Ingame.NewWorldParameters(2400, 800, HQRNG().nextLong()) + //ingame!!.gameLoadMode = Ingame.GameLoadMode.CREATE_NEW - LoadScreen.screenToLoad = ingame!! - super.setScreen(LoadScreen) + //LoadScreen.screenToLoad = ingame!! + + super.setScreen(TitleScreen(batch)) + //super.setScreen(LoadScreen) //super.setScreen(ingame) } @@ -423,6 +453,17 @@ object Terrarum : Game() { screenW = width screenH = height + + // re-calculate fullscreen quad + fullscreenQuad.setVertices(floatArrayOf( + 0f, 0f, 0f, 1f, 1f, 1f, 1f, 0f, 1f, + Terrarum.WIDTH.toFloat(), 0f, 0f, 1f, 1f, 1f, 1f, 1f, 1f, + Terrarum.WIDTH.toFloat(), Terrarum.HEIGHT.toFloat(), 0f, 1f, 1f, 1f, 1f, 1f, 0f, + 0f, Terrarum.HEIGHT.toFloat(), 0f, 1f, 1f, 1f, 1f, 0f, 0f + )) + fullscreenQuad.setIndices(shortArrayOf(0, 1, 2, 2, 3, 0)) + + super.screen.resize(WIDTH, HEIGHT) } diff --git a/src/net/torvald/terrarum/TitleScreen.kt b/src/net/torvald/terrarum/TitleScreen.kt new file mode 100644 index 000000000..f7c5e2d8c --- /dev/null +++ b/src/net/torvald/terrarum/TitleScreen.kt @@ -0,0 +1,363 @@ +package net.torvald.terrarum + +import com.badlogic.gdx.Gdx +import com.badlogic.gdx.Input +import com.badlogic.gdx.Screen +import com.badlogic.gdx.graphics.* +import com.badlogic.gdx.graphics.g2d.SpriteBatch +import com.badlogic.gdx.graphics.g2d.TextureRegion +import com.badlogic.gdx.graphics.glutils.FrameBuffer +import net.torvald.terrarum.gameactors.ActorWithBody +import net.torvald.terrarum.gameactors.Hitbox +import net.torvald.terrarum.gamecontroller.KeyToggler +import net.torvald.terrarum.gameworld.GameWorld +import net.torvald.terrarum.langpack.Lang +import net.torvald.terrarum.serialise.ReadLayerData +import net.torvald.terrarum.ui.UICanvas +import net.torvald.terrarum.ui.UIHandler +import net.torvald.terrarum.ui.UIStartMenu +import net.torvald.terrarum.weather.WeatherMixer +import net.torvald.terrarum.worlddrawer.BlocksDrawer +import net.torvald.terrarum.worlddrawer.FeaturesDrawer +import net.torvald.terrarum.worlddrawer.LightmapRenderer +import net.torvald.terrarum.worlddrawer.WorldCamera +import java.io.FileInputStream + +class TitleScreen(val batch: SpriteBatch) : Screen { + + var camera = OrthographicCamera(Terrarum.WIDTH.toFloat(), Terrarum.HEIGHT.toFloat()) + + // invert Y + fun initViewPort(width: Int, height: Int) { + //val width = if (width % 1 == 1) width + 1 else width + //val height = if (height % 1 == 1) height + 1 else width + + // Set Y to point downwards + camera.setToOrtho(true, width.toFloat(), height.toFloat()) + + // Update camera matrix + camera.update() + + // Set viewport to restrict drawing + Gdx.gl20.glViewport(0, 0, width, height) + } + + + private var loadDone = false + + private lateinit var demoWorld: GameWorld + private val cameraPlayer = object : ActorWithBody(RenderOrder.BEHIND) { + override fun drawBody(batch: SpriteBatch) { } + override fun drawGlow(batch: SpriteBatch) { } + override fun dispose() { } + override fun onActorValueChange(key: String, value: Any?) { } + override fun run() { } + + override fun update(delta: Float) { + // camera walk? + } + } + + private val gradWhiteTop = Color(0xf8f8f8ff.toInt()) + private val gradWhiteBottom = Color(0xd8d8d8ff.toInt()) + + private val lightFBOformat = Pixmap.Format.RGB888 + var lightmapFboA = FrameBuffer(lightFBOformat, Terrarum.WIDTH.div(Ingame.lightmapDownsample.toInt()), Terrarum.HEIGHT.div(Ingame.lightmapDownsample.toInt()), false) + var lightmapFboB = FrameBuffer(lightFBOformat, Terrarum.WIDTH.div(Ingame.lightmapDownsample.toInt()), Terrarum.HEIGHT.div(Ingame.lightmapDownsample.toInt()), false) + + lateinit var logo: TextureRegion + + + private lateinit var uiMenu: UIHandler + + private fun loadThingsWhileIntroIsVisible() { + demoWorld = ReadLayerData(FileInputStream(ModMgr.getFile("basegame", "demoworld"))) + + cameraPlayer.hitbox.setPosition( + demoWorld.spawnX * FeaturesDrawer.TILE_SIZE.toDouble(), + demoWorld.spawnY * FeaturesDrawer.TILE_SIZE.toDouble() + ) + cameraPlayer.hitbox.setDimension(2.0, 2.0) + + demoWorld.time.timeDelta = 45 + + + LightmapRenderer.world = demoWorld + BlocksDrawer.world = demoWorld + FeaturesDrawer.world = demoWorld + + + uiMenu = UIHandler(UIStartMenu()) + uiMenu.setPosition(0, UIStartMenu.menubarOffY) + uiMenu.setAsOpen() + + + loadDone = true + } + + + override fun hide() { + } + + override fun show() { + initViewPort(Terrarum.WIDTH, Terrarum.HEIGHT) + + logo = TextureRegion(Texture(Gdx.files.internal("assets/graphics/logo_placeholder.tga"))) + logo.flip(false, true) + } + + private var blurWriteBuffer = lightmapFboA + private var blurReadBuffer = lightmapFboB + + private val minimumIntroTime = 1.0f + private var deltaCounter = 0f + + override fun render(delta: Float) { + Gdx.gl.glClearColor(.094f, .094f, .094f, 0f) + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) + + if (!loadDone || deltaCounter < minimumIntroTime) { + // draw load screen + Terrarum.shaderBayerSkyboxFill.begin() + Terrarum.shaderBayerSkyboxFill.setUniformMatrix("u_projTrans", camera.combined) + Terrarum.shaderBayerSkyboxFill.setUniformf("topColor", gradWhiteTop.r, gradWhiteTop.g, gradWhiteTop.b) + Terrarum.shaderBayerSkyboxFill.setUniformf("bottomColor", gradWhiteBottom.r, gradWhiteBottom.g, gradWhiteBottom.b) + Terrarum.fullscreenQuad.render(Terrarum.shaderBayerSkyboxFill, GL20.GL_TRIANGLES) + Terrarum.shaderBayerSkyboxFill.end() + + batch.inUse { + batch.color = Color.WHITE + blendNormal() + batch.shader = null + + + setCameraPosition(0f, 0f) + batch.draw(logo, (Terrarum.WIDTH - logo.regionWidth) / 2f, (Terrarum.HEIGHT - logo.regionHeight) / 2f) + } + + if (!loadDone) { + loadThingsWhileIntroIsVisible() + } + } + else { + //if (Terrarum.GLOBAL_RENDER_TIMER % 2 == 1) { + LightmapRenderer.fireRecalculateEvent() + //} + + + cameraPlayer.hitbox.setPosition(1024 * 16.0, 340 * 16.0) + + + demoWorld.updateWorldTime(delta) + WeatherMixer.update(delta, cameraPlayer) + cameraPlayer.update(delta) + // worldcamera update AFTER cameraplayer in this case; the other way is just an exception for actual ingame SFX + WorldCamera.update(demoWorld, cameraPlayer) + + + // update UIs // + uiMenu.update(delta) + + + // render and blur lightmap + //processBlur(LightmapRenderer.DRAW_FOR_RGB) + + // render world + batch.inUse { + batch.shader = null + camera.position.set(WorldCamera.gdxCamX, WorldCamera.gdxCamY, 0f) // make camara work + camera.update() + batch.projectionMatrix = camera.combined + batch.color = Color.WHITE + blendNormal() + + + + renderDemoWorld() + + renderMenus() + + renderOverlayTexts() + } + + } + + + + deltaCounter += delta + } + + private fun renderDemoWorld() { + // draw skybox // + + setCameraPosition(0f, 0f) + batch.color = Color.WHITE + blendNormal() + WeatherMixer.render(camera, demoWorld) + + + // draw tiles // + + // using custom code for camera; this is obscure and tricky + camera.position.set(WorldCamera.gdxCamX, WorldCamera.gdxCamY, 0f) // make camara work + camera.update() + batch.projectionMatrix = camera.combined + batch.shader = null + + blendNormal() + BlocksDrawer.renderWall(batch) + BlocksDrawer.renderTerrain(batch) + BlocksDrawer.renderFront(batch, false) + FeaturesDrawer.drawEnvOverlay(batch) + } + + private fun renderMenus() { + setCameraPosition(0f, 0f) + blendNormal() + batch.shader = null + + + uiMenu.render(batch, camera) + } + + private fun renderOverlayTexts() { + setCameraPosition(0f, 0f) + blendNormal() + batch.shader = null + + batch.color = Color.LIGHT_GRAY + + val COPYTING = arrayOf( + COPYRIGHT_DATE_NAME, + Lang["COPYRIGHT_GNU_GPL_3"] + ) + + COPYTING.forEachIndexed { index, s -> + val textWidth = Terrarum.fontGame.getWidth(s) + Terrarum.fontGame.draw(batch, s, + Terrarum.WIDTH - textWidth - 1f - 0.667f, + Terrarum.HEIGHT - Terrarum.fontGame.lineHeight * (COPYTING.size - index) - 1f + ) + } + } + + override fun pause() { + } + + override fun resume() { + } + + override fun resize(width: Int, height: Int) { + // Set up viewport when window is resized + initViewPort(width, height) + } + + override fun dispose() { + logo.texture.dispose() + lightmapFboA.dispose() + lightmapFboB.dispose() + + uiMenu.dispose() + } + + fun setCameraPosition(newX: Float, newY: Float) { + Ingame.setCameraPosition(batch, camera, newX, newY) + } + + + fun processBlur(mode: Int) { + val blurIterations = 5 // ideally, 4 * radius; must be even/odd number -- odd/even number will flip the image + val blurRadius = 4f / Ingame.lightmapDownsample // (5, 4f); using low numbers for pixel-y aesthetics + + blurWriteBuffer = lightmapFboA + blurReadBuffer = lightmapFboB + + + lightmapFboA.inAction(null, null) { + Gdx.gl.glClearColor(0f, 0f, 0f, 0f) + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) + } + lightmapFboB.inAction(null, null) { + Gdx.gl.glClearColor(0f, 0f, 0f, 0f) + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) + } + + + if (mode == LightmapRenderer.DRAW_FOR_RGB) { + // initialise readBuffer with untreated lightmap + blurReadBuffer.inAction(camera, batch) { + batch.inUse { + // using custom code for camera; this is obscure and tricky + camera.position.set( + (WorldCamera.gdxCamX / Ingame.lightmapDownsample).round(), + (WorldCamera.gdxCamY / Ingame.lightmapDownsample).round(), + 0f + ) // make camara work + camera.update() + batch.projectionMatrix = camera.combined + + + blendNormal() + batch.color = Color.WHITE + LightmapRenderer.draw(batch, LightmapRenderer.DRAW_FOR_RGB) + } + } + } + else { + // initialise readBuffer with untreated lightmap + blurReadBuffer.inAction(camera, batch) { + batch.inUse { + // using custom code for camera; this is obscure and tricky + camera.position.set( + (WorldCamera.gdxCamX / Ingame.lightmapDownsample).round(), + (WorldCamera.gdxCamY / Ingame.lightmapDownsample).round(), + 0f + ) // make camara work + camera.update() + batch.projectionMatrix = camera.combined + + + blendNormal() + batch.color = Color.WHITE + LightmapRenderer.draw(batch, LightmapRenderer.DRAW_FOR_ALPHA) + } + } + } + + + + for (i in 0 until blurIterations) { + blurWriteBuffer.inAction(camera, batch) { + + batch.inUse { + val texture = blurReadBuffer.colorBufferTexture + + texture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear) + + + batch.shader = Terrarum.shaderBlur + batch.shader.setUniformf("iResolution", + blurWriteBuffer.width.toFloat(), blurWriteBuffer.height.toFloat()) + batch.shader.setUniformf("flip", 1f) + if (i % 2 == 0) + batch.shader.setUniformf("direction", blurRadius, 0f) + else + batch.shader.setUniformf("direction", 0f, blurRadius) + + + batch.color = Color.WHITE + batch.draw(texture, 0f, 0f) + + + // swap + val t = blurWriteBuffer + blurWriteBuffer = blurReadBuffer + blurReadBuffer = t + } + } + } + + } + + +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/blockproperties/BlockPropUtil.kt b/src/net/torvald/terrarum/blockproperties/BlockPropUtil.kt index ea4701520..cb6eff15d 100644 --- a/src/net/torvald/terrarum/blockproperties/BlockPropUtil.kt +++ b/src/net/torvald/terrarum/blockproperties/BlockPropUtil.kt @@ -94,8 +94,8 @@ object BlockPropUtil { fun getDynamicLumFunc(baseLum: Color, type: Int): Color { return when (type) { 1 -> getTorchFlicker(baseLum) - 2 -> Terrarum.ingame!!.world.globalLight // current global light - 3 -> WeatherMixer.getGlobalLightOfTime(WorldTime.DAY_LENGTH / 2) // daylight at noon + 2 -> Terrarum.ingame!!.world.globalLight.cpy().mul(LightmapRenderer.DIV_FLOAT) // current global light + 3 -> WeatherMixer.getGlobalLightOfTime(WorldTime.DAY_LENGTH / 2).cpy().mul(LightmapRenderer.DIV_FLOAT) // daylight at noon 4 -> getSlowBreath(baseLum) 5 -> getPulsate(baseLum) else -> baseLum diff --git a/src/net/torvald/terrarum/console/CommandDict.kt b/src/net/torvald/terrarum/console/CommandDict.kt index 8f445363a..d9e1f9042 100644 --- a/src/net/torvald/terrarum/console/CommandDict.kt +++ b/src/net/torvald/terrarum/console/CommandDict.kt @@ -51,7 +51,11 @@ object CommandDict { "spawntorch" to SpawnTikiTorch, "musictest" to MusicTest, "spawntapestry" to SpawnTapestry, - "imtest" to JavaIMTest + "imtest" to JavaIMTest, + + + /* !! */"exportlayer" to ExportLayerData, + /* !! */"importlayer" to ImportLayerData ) operator fun get(commandName: String): ConsoleCommand { diff --git a/src/net/torvald/terrarum/console/EchoError.kt b/src/net/torvald/terrarum/console/EchoError.kt index 595645406..5af9c0105 100644 --- a/src/net/torvald/terrarum/console/EchoError.kt +++ b/src/net/torvald/terrarum/console/EchoError.kt @@ -1,6 +1,7 @@ package net.torvald.terrarum.console import net.torvald.terrarum.Terrarum +import net.torvald.terrarum.ccR import net.torvald.terrarum.ui.ConsoleWindow /** @@ -13,7 +14,7 @@ internal object EchoError : ConsoleCommand { } fun execute(single_line: String) { - (Terrarum.ingame!!.consoleHandler.UI as ConsoleWindow).sendMessage(single_line) + (Terrarum.ingame!!.consoleHandler.UI as ConsoleWindow).sendMessage("$ccR$single_line") } operator fun invoke(args: Array) = execute(args) diff --git a/src/net/torvald/terrarum/console/ExportLayerData.kt b/src/net/torvald/terrarum/console/ExportLayerData.kt new file mode 100644 index 000000000..d377543b6 --- /dev/null +++ b/src/net/torvald/terrarum/console/ExportLayerData.kt @@ -0,0 +1,26 @@ +package net.torvald.terrarum.console + +import net.torvald.terrarum.serialise.WriteLayerData +import net.torvald.terrarum.serialise.WriteMeta + +/** + * Created by minjaesong on 2017-07-18. + */ +object ExportLayerData : ConsoleCommand { + override fun execute(args: Array) { + if (args.size < 2) { + printUsage() + return + } + + val saveDirectoryName = args[1] + + WriteLayerData(saveDirectoryName) + + Echo("Layer data exported to $saveDirectoryName/${WriteLayerData.META_FILENAME}") + } + + override fun printUsage() { + Echo("Usage: exportlayer savename") + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/console/ImportLayerData.kt b/src/net/torvald/terrarum/console/ImportLayerData.kt new file mode 100644 index 000000000..27e856f22 --- /dev/null +++ b/src/net/torvald/terrarum/console/ImportLayerData.kt @@ -0,0 +1,33 @@ +package net.torvald.terrarum.console + +import net.torvald.terrarum.Terrarum +import net.torvald.terrarum.serialise.ReadLayerData +import net.torvald.terrarum.worlddrawer.FeaturesDrawer +import java.io.FileInputStream +import java.util.zip.GZIPInputStream + +/** + * Created by minjaesong on 2017-07-18. + */ +object ImportLayerData : ConsoleCommand { + override fun execute(args: Array) { + if (args.size < 2) { + ExportLayerData.printUsage() + return + } + + //val fis = GZIPInputStream(FileInputStream(args[1])) // this gzip is kaput + val fis = FileInputStream(args[1]) + Terrarum.ingame!!.world = ReadLayerData(fis) + Terrarum.ingame!!.player.setPosition( + Terrarum.ingame!!.world.spawnY * FeaturesDrawer.TILE_SIZE.toDouble(), + Terrarum.ingame!!.world.spawnX * FeaturesDrawer.TILE_SIZE.toDouble() + ) + fis.close() + Echo("Successfully loaded ${args[1]}") + } + + override fun printUsage() { + Echo("Usage: importlayer path/to/layer.data") + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/gameactors/PlayerBuilderSigrid.kt b/src/net/torvald/terrarum/gameactors/PlayerBuilderSigrid.kt index d45fe7758..0c26b55c9 100644 --- a/src/net/torvald/terrarum/gameactors/PlayerBuilderSigrid.kt +++ b/src/net/torvald/terrarum/gameactors/PlayerBuilderSigrid.kt @@ -79,7 +79,7 @@ object PlayerBuilderSigrid { Block.STONE_QUARRIED, Block.STONE_TILE_WHITE, Block.TORCH, Block.DAYLIGHT_CAPACITOR, Block.ICE_FRAGILE, Block.ILLUMINATOR_WHITE, Block.ILLUMINATOR_BLACK, Block.ILLUMINATOR_ORANGE, - Block.ILLUMINATOR_GREEN + Block.ILLUMINATOR_GREEN, Block.ILLUMINATOR_CYAN, Block.SUNSTONE ) val walls = arrayOf( Block.AIR, Block.DIRT, Block.GLASS_CRUDE, diff --git a/src/net/torvald/terrarum/gameworld/GameWorld.kt b/src/net/torvald/terrarum/gameworld/GameWorld.kt index 6c3b7f30b..156324ce4 100644 --- a/src/net/torvald/terrarum/gameworld/GameWorld.kt +++ b/src/net/torvald/terrarum/gameworld/GameWorld.kt @@ -2,7 +2,6 @@ package net.torvald.terrarum.gameworld import com.badlogic.gdx.graphics.Color -import net.torvald.dataclass.Float16 import net.torvald.terrarum.realestate.LandUtil import net.torvald.terrarum.blockproperties.BlockCodex import org.dyn4j.geometry.Vector2 @@ -23,8 +22,10 @@ class GameWorld(val width: Int, val height: Int) { val layerThermal: MapLayerFloat // in Kelvins - val spawnX: Int - val spawnY: Int + /** Tilewise spawn point */ + var spawnX: Int + /** Tilewise spawn point */ + var spawnY: Int val wallDamages = HashMap() val terrainDamages = HashMap() @@ -73,7 +74,7 @@ class GameWorld(val width: Int, val height: Int) { * @return byte[][] terrain layer */ - val terrainArray: Array + val terrainArray: ByteArray get() = layerTerrain.data /** @@ -81,7 +82,7 @@ class GameWorld(val width: Int, val height: Int) { * @return byte[][] wall layer */ - val wallArray: Array + val wallArray: ByteArray get() = layerWall.data /** @@ -89,7 +90,7 @@ class GameWorld(val width: Int, val height: Int) { * @return byte[][] wire layer */ - val wireArray: Array + val wireArray: ByteArray get() = layerWire.data /** @@ -97,8 +98,8 @@ class GameWorld(val width: Int, val height: Int) { * Format: 0baaaabbbb, aaaa for x = 0, 2, 4, ..., bbbb for x = 1, 3, 5, ... * @return byte[][] damage code pair */ - val damageDataArray: Array - get() = layerTerrainLowBits.dataPair + val damageDataArray: ByteArray + get() = layerTerrainLowBits.data fun getTileFromWall(x: Int, y: Int): Int? { val wall: Int? = layerWall.getTile(x fmod width, y) @@ -167,7 +168,7 @@ class GameWorld(val width: Int, val height: Int) { } fun setTileWire(x: Int, y: Int, tile: Byte) { - layerWire.data[y][x fmod width] = tile + layerWire.setTile(x fmod width, y, tile) } fun getTileFrom(mode: Int, x: Int, y: Int): Int? { diff --git a/src/net/torvald/terrarum/gameworld/MapLayer.kt b/src/net/torvald/terrarum/gameworld/MapLayer.kt index 87d83c1d2..406b857a7 100644 --- a/src/net/torvald/terrarum/gameworld/MapLayer.kt +++ b/src/net/torvald/terrarum/gameworld/MapLayer.kt @@ -1,14 +1,16 @@ package net.torvald.terrarum.gameworld +import net.torvald.terrarum.virtualcomputer.tvd.ByteArray64 + /** * Created by minjaesong on 16-01-17. */ class MapLayer(val width: Int, val height: Int) : Iterable { - internal @Volatile var data: Array // in parallel programming: do not trust your register; always read freshly from RAM! + internal @Volatile var data: ByteArray // in parallel programming: do not trust your register; always read freshly from RAM! init { - data = Array(height) { ByteArray(width) } + data = ByteArray(width * height) } /** @@ -31,7 +33,7 @@ class MapLayer(val width: Int, val height: Int) : Iterable { // advance counter iteratorCount += 1 - return data[y][x] + return data[y * width + x] } } } @@ -40,11 +42,11 @@ class MapLayer(val width: Int, val height: Int) : Iterable { return if (x !in 0..width - 1 || y !in 0..height - 1) null else - data[y][x].toUint() + data[y * width + x].toUint() } internal fun setTile(x: Int, y: Int, tile: Byte) { - data[y][x] = tile + data[y * width + x] = tile } fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height) diff --git a/src/net/torvald/terrarum/gameworld/PairedMapLayer.kt b/src/net/torvald/terrarum/gameworld/PairedMapLayer.kt index 19d10d5d6..e909254e9 100644 --- a/src/net/torvald/terrarum/gameworld/PairedMapLayer.kt +++ b/src/net/torvald/terrarum/gameworld/PairedMapLayer.kt @@ -1,9 +1,5 @@ package net.torvald.terrarum.gameworld -import java.io.Serializable -import java.util.Spliterator -import java.util.function.Consumer - /** * Created by minjaesong on 16-02-15. */ @@ -17,14 +13,14 @@ class PairedMapLayer(width: Int, val height: Int) : Iterable { * 0110 1101 is interpreted as * 6 for tile 0, 13 for tile 1. */ - internal @Volatile var dataPair: Array + internal @Volatile var data: ByteArray val width: Int init { this.width = width / 2 - dataPair = Array(height) { ByteArray(width / 2) } + data = ByteArray(width * height / 2) } /** @@ -48,7 +44,7 @@ class PairedMapLayer(width: Int, val height: Int) : Iterable { // advance counter iteratorCount += 1 - return dataPair[y][x] + return data[y * width + x] } } } @@ -59,10 +55,10 @@ class PairedMapLayer(width: Int, val height: Int) : Iterable { else { if (x and 0x1 == 0) // higher four bits for i = 0, 2, 4, ... - (java.lang.Byte.toUnsignedInt(dataPair[y][x / 2]) and 0xF0) ushr 4 + (java.lang.Byte.toUnsignedInt(data[y * width + x / 2]) and 0xF0) ushr 4 else // lower four bits for i = 1, 3, 5, ... - java.lang.Byte.toUnsignedInt(dataPair[y][x / 2]) and 0x0F + java.lang.Byte.toUnsignedInt(data[y * width + x / 2]) and 0x0F } } @@ -70,12 +66,12 @@ class PairedMapLayer(width: Int, val height: Int) : Iterable { if (data < 0 || data >= 16) throw IllegalArgumentException("[PairedMapLayer] $data: invalid data value.") if (x and 0x1 == 0) // higher four bits for i = 0, 2, 4, ... - dataPair[y][x / 2] = - (java.lang.Byte.toUnsignedInt(dataPair[y][x / 2]) and 0x0F + this.data[y * width + x / 2] = + (java.lang.Byte.toUnsignedInt(this.data[y * width + x / 2]) and 0x0F or (data and 0xF shl 4)).toByte() else // lower four bits for i = 1, 3, 5, ... - dataPair[y][x / 2] = (java.lang.Byte.toUnsignedInt(dataPair[y][x / 2]) and 0xF0 + this.data[y * width + x / 2] = (java.lang.Byte.toUnsignedInt(this.data[y * width + x / 2]) and 0xF0 or (data and 0xF)).toByte() } diff --git a/src/net/torvald/terrarum/serialise/ReadGameMapData.kt b/src/net/torvald/terrarum/serialise/ReadGameMapData.kt deleted file mode 100644 index 6611df129..000000000 --- a/src/net/torvald/terrarum/serialise/ReadGameMapData.kt +++ /dev/null @@ -1,42 +0,0 @@ -package net.torvald.terrarum.serialise - -import java.io.IOException -import java.io.InputStream - -/** - * Created by minjaesong on 16-08-24. - */ -// internal for everything: prevent malicious module from messing up the savedata -internal object ReadGameMapData { - - internal fun InputStream.readRelative(b: ByteArray, off: Int, len: Int): Int { - if (b == null) { - throw NullPointerException() - } else if (off < 0 || len < 0 || len > b.size) { - throw IndexOutOfBoundsException() - } else if (len == 0) { - return 0 - } - - var c = read() - if (c == -1) { - return -1 - } - b[0] = c.toByte() - - var i = 1 - try { - while (i < len) { - c = read() - if (c == -1) { - break - } - b[i] = c.toByte() - i++ - } - } catch (ee: IOException) { - } - - return i - } -} \ No newline at end of file diff --git a/src/net/torvald/terrarum/serialise/ReadLayerData.kt b/src/net/torvald/terrarum/serialise/ReadLayerData.kt new file mode 100644 index 000000000..b41b206b3 --- /dev/null +++ b/src/net/torvald/terrarum/serialise/ReadLayerData.kt @@ -0,0 +1,114 @@ +package net.torvald.terrarum.serialise + +import net.torvald.terrarum.gameworld.GameWorld +import java.io.IOException +import java.io.InputStream +import java.lang.IllegalArgumentException +import java.util.* + +/** + * Created by minjaesong on 16-08-24. + */ +// internal for everything: prevent malicious module from messing up the savedata +internal object ReadLayerData { + + + internal operator fun invoke(inputStream: InputStream, inWorld: GameWorld? = null): GameWorld { + val magicBytes = ByteArray(4) + val layerSizeBytes = ByteArray(1) + val layerCountBytes = ByteArray(1) + val worldWidthBytes = ByteArray(4) + val worldHeightBytes = ByteArray(4) + val spawnCoordXBytes = ByteArray(4) + val spawnCoordYBytes = ByteArray(4) + + // read header first + inputStream.read(magicBytes) + if (!Arrays.equals(magicBytes, WriteLayerData.MAGIC)) { + throw IllegalArgumentException("File not a Layer Data") + } + + inputStream.read(layerSizeBytes) + inputStream.read(layerCountBytes) + inputStream.skip(2) // reserved bytes + inputStream.read(worldWidthBytes) + inputStream.read(worldHeightBytes) + inputStream.read(spawnCoordXBytes) + inputStream.read(spawnCoordYBytes) + + val worldWidth = worldWidthBytes.toLittleInt() + val worldHeight = worldHeightBytes.toLittleInt() + val bytesPerTile = layerSizeBytes[0].toUint() + val layerCount = layerCountBytes[0].toUint() + val layerSize = worldWidth * worldHeight * bytesPerTile + + val terrainLayerMSB = ByteArray(layerSize) + val wallLayerMSB = ByteArray(layerSize) + val terrainLayerLSB = ByteArray(layerSize / 2) + val wallLayerLSB = ByteArray(layerSize / 2) + var wireLayer: ByteArray? = null + + inputStream.read(terrainLayerMSB) + inputStream.read(wallLayerMSB) + inputStream.read(terrainLayerLSB) + inputStream.read(wallLayerLSB) + + if (layerCount == 4) { + wireLayer = ByteArray(layerSize) + inputStream.read(wireLayer) + } + + + + // create world out of tiles data + + val retWorld = inWorld ?: GameWorld(worldWidth, worldHeight) + + retWorld.layerTerrain.data = terrainLayerMSB + retWorld.layerWall.data = wallLayerMSB + retWorld.layerTerrainLowBits.data = terrainLayerLSB + retWorld.layerWallLowBits.data = wallLayerLSB + + if (wireLayer != null) { + retWorld.layerWire.data = wireLayer + } + + retWorld.spawnX = spawnCoordXBytes.toLittleInt() + retWorld.spawnY = spawnCoordYBytes.toLittleInt() + + + return retWorld + } + + + internal fun InputStream.readRelative(b: ByteArray, off: Int, len: Int): Int { + if (b == null) { + throw NullPointerException() + } else if (off < 0 || len < 0 || len > b.size) { + throw IndexOutOfBoundsException() + } else if (len == 0) { + return 0 + } + + var c = read() + if (c == -1) { + return -1 + } + b[0] = c.toByte() + + var i = 1 + try { + while (i < len) { + c = read() + if (c == -1) { + break + } + b[i] = c.toByte() + i++ + } + } catch (ee: IOException) { + } + + return i + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/serialise/WriteCSV.kt b/src/net/torvald/terrarum/serialise/WriteCSV.kt index 243273a9e..32f5f7179 100644 --- a/src/net/torvald/terrarum/serialise/WriteCSV.kt +++ b/src/net/torvald/terrarum/serialise/WriteCSV.kt @@ -48,7 +48,7 @@ internal object WriteCSV { Files.copy(tempPathMat, pathMat, StandardCopyOption.REPLACE_EXISTING) Files.deleteIfExists(tempPathMat) - println("Saved map data '${WriteGameMapData.META_FILENAME}' to $saveDirectoryName.") + println("Saved map data '${WriteLayerData.META_FILENAME}' to $saveDirectoryName.") return true } diff --git a/src/net/torvald/terrarum/serialise/WriteGameMapData.kt b/src/net/torvald/terrarum/serialise/WriteGameMapData.kt deleted file mode 100644 index 39cbfd9ef..000000000 --- a/src/net/torvald/terrarum/serialise/WriteGameMapData.kt +++ /dev/null @@ -1,75 +0,0 @@ -package net.torvald.terrarum.serialise - -import net.torvald.terrarum.gameworld.GameWorld -import net.torvald.terrarum.Terrarum -import java.io.IOException -import java.nio.charset.Charset -import java.nio.file.Files -import java.nio.file.Paths -import java.nio.file.StandardCopyOption - -/** - * Created by minjaesong on 16-03-18. - */ -// internal for everything: prevent malicious module from messing up the savedata -internal object WriteGameMapData { - - val META_FILENAME = "worldinfo1" - - val MAGIC = "TEMD".toByteArray(charset = Charset.forName("US-ASCII")) - - val BYTE_NULL: Byte = 0 - - - internal fun write(saveDirectoryName: String): Boolean { - val path = Paths.get("${Terrarum.defaultSaveDir}" + - "/$saveDirectoryName/${WriteMeta.META_FILENAME}") - val tempPath = Files.createTempFile(path.toString(), "_temp") - val map = Terrarum.ingame!!.world - - // TODO gzip - - // write binary - Files.write(tempPath, MAGIC) - Files.write(tempPath, byteArrayOf(GameWorld.SIZEOF)) - Files.write(tempPath, byteArrayOf(GameWorld.LAYERS)) - Files.write(tempPath, byteArrayOf(BYTE_NULL)) - Files.write(tempPath, byteArrayOf(BYTE_NULL)) - Files.write(tempPath, toByteArray(map.width)) - Files.write(tempPath, toByteArray(map.height)) - Files.write(tempPath, toByteArray(map.spawnX)) - Files.write(tempPath, toByteArray(map.spawnY)) - map.layerTerrain.forEach( - { b -> Files.write(tempPath, byteArrayOf(b)) }) - map.layerWall.forEach( - { b -> Files.write(tempPath, byteArrayOf(b)) }) - map.layerTerrainLowBits.forEach( - { b -> Files.write(tempPath, byteArrayOf(b)) }) - map.layerWallLowBits.forEach( - { b -> Files.write(tempPath, byteArrayOf(b)) }) - map.layerWire.forEach( - { b -> Files.write(tempPath, byteArrayOf(b)) }) - - // replace savemeta with tempfile - try { - Files.copy(tempPath, path, StandardCopyOption.REPLACE_EXISTING) - Files.deleteIfExists(tempPath) - println("Saved map data '$META_FILENAME' to $saveDirectoryName.") - - return true - } - catch (e: IOException) { - e.printStackTrace() - } - return false - } - - fun toByteArray(int: Int): ByteArray { - return byteArrayOf( - ((int ushr 0x18) and 0xFF).toByte(), - ((int ushr 0x10) and 0xFF).toByte(), - ((int ushr 0x08) and 0xFF).toByte(), - ((int ) and 0xFF).toByte() - ) - } -} \ No newline at end of file diff --git a/src/net/torvald/terrarum/serialise/WriteLayerData.kt b/src/net/torvald/terrarum/serialise/WriteLayerData.kt new file mode 100644 index 000000000..55f95c71c --- /dev/null +++ b/src/net/torvald/terrarum/serialise/WriteLayerData.kt @@ -0,0 +1,126 @@ +package net.torvald.terrarum.serialise + +import net.torvald.terrarum.gameworld.GameWorld +import net.torvald.terrarum.Terrarum +import net.torvald.terrarum.console.EchoError +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.nio.charset.Charset +import java.util.zip.GZIPOutputStream + +/** + * Created by minjaesong on 16-03-18. + */ +// internal for everything: prevent malicious module from messing up the savedata +internal object WriteLayerData { + + val META_FILENAME = "worldinfo1" + + val MAGIC = "TEMD".toByteArray(charset = Charset.forName("US-ASCII")) + + val BYTE_NULL: Byte = 0 + + + internal operator fun invoke(saveDirectoryName: String): Boolean { + val path = "${Terrarum.defaultSaveDir}/$saveDirectoryName/${META_FILENAME}" + val tempPath = "${path}_bak" + val map = Terrarum.ingame!!.world + + val parentDir = File("${Terrarum.defaultSaveDir}/$saveDirectoryName") + if (!parentDir.exists()) { + parentDir.mkdir() + } + else if (!parentDir.isDirectory) { + EchoError("Savegame directory is not actually a directory, aborting...") + return false + } + + val tempFile = File(tempPath) + val outFile = File(path) + tempFile.createNewFile() + + val outputStream = GZIPOutputStream(FileOutputStream(tempFile)) + + + // write binary + outputStream.write(MAGIC) + outputStream.write(byteArrayOf(GameWorld.SIZEOF)) + outputStream.write(byteArrayOf(GameWorld.LAYERS)) + outputStream.write(byteArrayOf(BYTE_NULL)) + outputStream.write(byteArrayOf(BYTE_NULL)) + outputStream.write(map.width.toLittle()) + outputStream.write(map.height.toLittle()) + outputStream.write(map.spawnX.toLittle()) + outputStream.write(map.spawnY.toLittle()) + // write one row (byteArray) at a time + outputStream.write(map.layerTerrain.data) + outputStream.write(map.layerWall.data) + outputStream.write(map.layerTerrainLowBits.data) + outputStream.write(map.layerWallLowBits.data) + outputStream.write(map.layerWire.data) + + // replace savemeta with tempfile + try { + outputStream.flush() + outputStream.close() + + outFile.delete() + tempFile.copyTo(outFile, overwrite = true) + tempFile.delete() + println("Saved map data '$META_FILENAME' to $saveDirectoryName.") + + return true + } + catch (e: IOException) { + e.printStackTrace() + } + finally { + outputStream.close() + } + + return false + } + + +} + +fun Int.toLittle() = byteArrayOf( + this.and(0xFF).toByte(), + this.ushr(8).and(0xFF).toByte(), + this.ushr(16).and(0xFF).toByte(), + this.ushr(24).and(0xFF).toByte() +) +fun Long.toLittle() = byteArrayOf( + this.and(0xFF).toByte(), + this.ushr(8).and(0xFF).toByte(), + this.ushr(16).and(0xFF).toByte(), + this.ushr(24).and(0xFF).toByte(), + this.ushr(32).and(0xFF).toByte(), + this.ushr(40).and(0xFF).toByte(), + this.ushr(48).and(0xFF).toByte(), + this.ushr(56).and(0xFF).toByte() +) +fun Double.toLittle() = java.lang.Double.doubleToRawLongBits(this).toLittle() +fun Boolean.toLittle() = byteArrayOf(if (this) 0xFF.toByte() else 0.toByte()) + +fun ByteArray.toLittleInt() = + if (this.size != 4) throw Error("Array not in size of 4") + else this[0].toUint() or + this[1].toUint().shl(8) or + this[2].toUint().shl(16) or + this[3].toUint().shl(24) +fun ByteArray.toLittleLong() = + if (this.size != 8) throw Error("Array not in size of 8") + else this[0].toUlong() or + this[1].toUlong().shl(8) or + this[2].toUlong().shl(16) or + this[3].toUlong().shl(24) or + this[4].toUlong().shl(32) or + this[5].toUlong().shl(40) or + this[6].toUlong().shl(48) or + this[7].toUlong().shl(56) +fun ByteArray.toLittleDouble() = java.lang.Double.longBitsToDouble(this.toLittleLong()) + +fun Byte.toUlong() = java.lang.Byte.toUnsignedLong(this) +fun Byte.toUint() = java.lang.Byte.toUnsignedInt(this) \ No newline at end of file diff --git a/src/net/torvald/terrarum/ui/UICanvas.kt b/src/net/torvald/terrarum/ui/UICanvas.kt index 09ead1279..a3329e7fd 100644 --- a/src/net/torvald/terrarum/ui/UICanvas.kt +++ b/src/net/torvald/terrarum/ui/UICanvas.kt @@ -8,6 +8,8 @@ import net.torvald.terrarum.gameactors.roundInt /** + * UIItems must be added manually at the init! + * * Created by minjaesong on 15-12-31. */ abstract class UICanvas { diff --git a/src/net/torvald/terrarum/ui/UIHandler.kt b/src/net/torvald/terrarum/ui/UIHandler.kt index df26b4a9c..21abd8bf9 100644 --- a/src/net/torvald/terrarum/ui/UIHandler.kt +++ b/src/net/torvald/terrarum/ui/UIHandler.kt @@ -1,16 +1,19 @@ package net.torvald.terrarum.ui +import com.badlogic.gdx.graphics.Camera import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.g2d.SpriteBatch +import net.torvald.terrarum.Ingame import net.torvald.terrarum.Terrarum import net.torvald.terrarum.gamecontroller.KeyToggler +import net.torvald.terrarum.round /** * UIHandler is a handler for UICanvas. It opens/closes the attached UI, moves the "window" (or "canvas") * to the coordinate of displayed cartesian coords, and update and render the UI. * It also process game inputs and send control events to the UI so that the UI can handle them. * - * Newly created UI is invisible by default. + * New UIs are NORMALLY HIDDEN; set it visible as you need! * * Created by minjaesong on 15-12-31. */ @@ -129,7 +132,7 @@ class UIHandler(var UI: UICanvas, } } - fun render(batch: SpriteBatch) { + fun render(batch: SpriteBatch, camera: Camera) { if (isVisible || alwaysVisible) { // camera SHOULD BE CENTERED to HALFX and HALFY (see StateInGame) // @@ -141,8 +144,9 @@ class UIHandler(var UI: UICanvas, - if (!customPositioning) - Terrarum.ingame?.setCameraPosition(posX.toFloat(), posY.toFloat()) + if (!customPositioning) { + setCameraPosition(batch, camera, posX.toFloat(), posY.toFloat()) + } batch.color = Color.WHITE UI.render(batch) @@ -289,4 +293,8 @@ class UIHandler(var UI: UICanvas, fun dispose() { UI.dispose() } + + fun setCameraPosition(batch: SpriteBatch, camera: Camera, newX: Float, newY: Float) { + Ingame.setCameraPosition(batch, camera, newX, newY) + } } diff --git a/src/net/torvald/terrarum/ui/UIInventory.kt b/src/net/torvald/terrarum/ui/UIInventory.kt index 6399c7272..ab0f1bce9 100644 --- a/src/net/torvald/terrarum/ui/UIInventory.kt +++ b/src/net/torvald/terrarum/ui/UIInventory.kt @@ -159,7 +159,7 @@ class UIInventory( else "${0xe069.toChar()} ${Lang["GAME_ACTION_CLOSE"]}" - private var oldCatSelect = -1 + private var oldCatSelect: Int? = null private var encumbrancePerc = 0f private var isEncumbered = false @@ -294,70 +294,72 @@ class UIInventory( fun shutUpAndRebuild() { - val filter = catButtonsToCatIdent[catButtons.selectedButton.labelText] + if (catButtons.selectedButton != null) { + val filter = catButtonsToCatIdent[catButtons.selectedButton!!.labelText] - // encumbrance - encumbrancePerc = inventory!!.capacity.toFloat() / inventory!!.maxCapacity - isEncumbered = inventory!!.isEncumbered + // encumbrance + encumbrancePerc = inventory!!.capacity.toFloat() / inventory!!.maxCapacity + isEncumbered = inventory!!.isEncumbered - inventorySortList = ArrayList() + inventorySortList = ArrayList() - // filter items - inventory?.forEach { - if (it.item.inventoryCategory == filter || filter == "__all__") - inventorySortList.add(it) - } + // filter items + inventory?.forEach { + if (it.item.inventoryCategory == filter || filter == "__all__") + inventorySortList.add(it) + } - rebuildList = false + rebuildList = false - // sort if needed - // test sort by name - inventorySortList.sortBy { it.item.name } + // sort if needed + // test sort by name + inventorySortList.sortBy { it.item.name } - // map sortList to item list - for (k in 0..items.size - 1) { - // we have an item - try { - val sortListItem = inventorySortList[k + itemPage * items.size] - items[k].item = sortListItem.item - items[k].amount = sortListItem.amount - items[k].itemImage = ItemCodex.getItemImage(sortListItem.item) + // map sortList to item list + for (k in 0..items.size - 1) { + // we have an item + try { + val sortListItem = inventorySortList[k + itemPage * items.size] + items[k].item = sortListItem.item + items[k].amount = sortListItem.amount + items[k].itemImage = ItemCodex.getItemImage(sortListItem.item) - // set quickslot number - for (qs in 1..UIQuickBar.SLOT_COUNT) { - if (sortListItem.item == actor?.inventory?.getQuickBar(qs - 1)?.item) { - items[k].quickslot = qs % 10 // 10 -> 0, 1..9 -> 1..9 - break - } - else - items[k].quickslot = null - } - - // set equippedslot number - for (eq in 0..actor!!.inventory.itemEquipped.size - 1) { - if (eq < actor!!.inventory.itemEquipped.size) { - if (actor!!.inventory.itemEquipped[eq] == items[k].item) { - items[k].equippedSlot = eq + // set quickslot number + for (qs in 1..UIQuickBar.SLOT_COUNT) { + if (sortListItem.item == actor?.inventory?.getQuickBar(qs - 1)?.item) { + items[k].quickslot = qs % 10 // 10 -> 0, 1..9 -> 1..9 break } else - items[k].equippedSlot = null + items[k].quickslot = null + } + + // set equippedslot number + for (eq in 0..actor!!.inventory.itemEquipped.size - 1) { + if (eq < actor!!.inventory.itemEquipped.size) { + if (actor!!.inventory.itemEquipped[eq] == items[k].item) { + items[k].equippedSlot = eq + break + } + else + items[k].equippedSlot = null + } } } + // we do not have an item, empty the slot + catch (e: IndexOutOfBoundsException) { + items[k].item = null + items[k].amount = 0 + items[k].itemImage = null + items[k].quickslot = null + } } - // we do not have an item, empty the slot - catch (e: IndexOutOfBoundsException) { - items[k].item = null - items[k].amount = 0 - items[k].itemImage = null - items[k].quickslot = null - } + + + itemPageCount = maxOf(1, 1 + (inventorySortList.size.minus(1) / items.size)) } - - - itemPageCount = maxOf(1, 1 + (inventorySortList.size.minus(1) / items.size)) } diff --git a/src/net/torvald/terrarum/ui/UIItem.kt b/src/net/torvald/terrarum/ui/UIItem.kt index 246ac517c..6420a3fd4 100644 --- a/src/net/torvald/terrarum/ui/UIItem.kt +++ b/src/net/torvald/terrarum/ui/UIItem.kt @@ -6,6 +6,32 @@ import net.torvald.terrarum.Terrarum /** + * ## Attaching Input Listeners + * + * UIItem provides following listeners: + * + * - updateListener + * - keyDownListener + * - keyUpListener + * - mouseMovedListene + * - touchDraggedListe + * - touchDownListener + * - touchUpListener + * - scrolledListener + * - clickOnceListener + * + * Each listeners are implemented using _functions_, instead of traditional listener _classes_. + * What you should do is just override one or more of these variables which has 'function' as their type. + * For example: + * + * ``` + * <>.clickOnceListener = { mouseX, mouseY, button -> + * println("Bo-ing!") + * } + * ``` + * + * This listener will print out 'Bo-ing!' whenever it's clicked. + * * Created by minjaesong on 15-12-31. */ abstract class UIItem(var parentUI: UICanvas) { // do not replace parentUI to UIHandler! @@ -88,6 +114,8 @@ abstract class UIItem(var parentUI: UICanvas) { // do not replace parentUI to UI return false } open fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean { + println("trsaneirsatneioarsteniotrsaneioarstineoarstneio") + var actionDone = false if (touchDownListener != null) { diff --git a/src/net/torvald/terrarum/ui/UIItemTextButtonList.kt b/src/net/torvald/terrarum/ui/UIItemTextButtonList.kt index 3b2913e8a..6bc61a5df 100644 --- a/src/net/torvald/terrarum/ui/UIItemTextButtonList.kt +++ b/src/net/torvald/terrarum/ui/UIItemTextButtonList.kt @@ -16,11 +16,11 @@ import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack class UIItemTextButtonList( parentUI: UICanvas, labelsList: Array, - override val width: Int, - override val height: Int, + override var width: Int, + override var height: Int, val verticalGutter: Int = 0, val readFromLang: Boolean = false, - val defaultSelection: Int = 0, + val defaultSelection: Int? = null, // negative: INVALID, positive: valid, null: no select // icons val textAreaWidth: Int, @@ -36,7 +36,7 @@ class UIItemTextButtonList( val highlightBackCol: Color = Color(0xb0b0b0_ff.toInt()), val highlightBackBlendMode: String = BlendMode.MULTIPLY, val inactiveCol: Color = Color(0xc0c0c0_ff.toInt()), - val backgroundCol: Color = Color(0), + val backgroundCol: Color = Color(0x242424_80), val backgroundBlendMode: String = BlendMode.NORMAL, val kinematic: Boolean = false ) : UIItem(parentUI) { @@ -93,10 +93,10 @@ class UIItemTextButtonList( override var posX = 0 override var posY = 0 - var selectedIndex = defaultSelection - val selectedButton: UIItemTextButton - get() = buttons[selectedIndex] - private var highlightY = buttons[selectedIndex].posY.toDouble() + var selectedIndex: Int? = defaultSelection + val selectedButton: UIItemTextButton? + get() = if (selectedIndex != null) buttons[selectedIndex!!] else null + private var highlightY: Double? = if (selectedIndex != null) buttons[selectedIndex!!].posY.toDouble() else null private val highlighterMoveDuration: Second = 0.1f private var highlighterMoveTimer: Second = 0f private var highlighterMoving = false @@ -107,12 +107,15 @@ class UIItemTextButtonList( override fun update(delta: Float) { if (highlighterMoving) { highlighterMoveTimer += delta - highlightY = UIUtils.moveQuick( - highlighterYStart, - highlighterYEnd, - highlighterMoveTimer.toDouble(), - highlighterMoveDuration.toDouble() - ) + + if (selectedIndex != null) { + highlightY = UIUtils.moveQuick( + highlighterYStart!!, + highlighterYEnd!!, + highlighterMoveTimer.toDouble(), + highlighterMoveDuration.toDouble() + ) + } if (highlighterMoveTimer > highlighterMoveDuration) { highlighterMoveTimer = 0f @@ -128,14 +131,14 @@ class UIItemTextButtonList( if (btn.mousePushed && index != selectedIndex) { if (kinematic) { - highlighterYStart = buttons[selectedIndex].posY.toDouble() + highlighterYStart = buttons[selectedIndex!!].posY.toDouble() selectedIndex = index highlighterMoving = true - highlighterYEnd = buttons[selectedIndex].posY.toDouble() + highlighterYEnd = buttons[selectedIndex!!].posY.toDouble() } else { selectedIndex = index - highlightY = buttons[selectedIndex].posY.toDouble() + highlightY = buttons[selectedIndex!!].posY.toDouble() } } btn.highlighted = (index == selectedIndex) // forcibly highlight if this.highlighted != null @@ -150,7 +153,9 @@ class UIItemTextButtonList( batch.color = highlightBackCol BlendMode.resolve(highlightBackBlendMode) - batch.fillRect(posX.toFloat(), highlightY.toFloat(), width.toFloat(), UIItemTextButton.height.toFloat()) + if (highlightY != null) { + batch.fillRect(posX.toFloat(), highlightY!!.toFloat(), width.toFloat(), UIItemTextButton.height.toFloat()) + } buttons.forEach { it.render(batch) } diff --git a/src/net/torvald/terrarum/ui/UIStartMenu.kt b/src/net/torvald/terrarum/ui/UIStartMenu.kt new file mode 100644 index 000000000..570841a10 --- /dev/null +++ b/src/net/torvald/terrarum/ui/UIStartMenu.kt @@ -0,0 +1,107 @@ +package net.torvald.terrarum.ui + +import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.graphics.g2d.SpriteBatch +import net.torvald.terrarum.Terrarum + +class UIStartMenu : UICanvas() { + + companion object { + /** Contains STRING_IDs */ + val menuLabels = arrayOf( + "MENU_MODE_SINGLEPLAYER", + "MENU_OPTIONS", + "MENU_MODULES", + "MENU_LABEL_EXIT" + ) + + val menubarOffY = Terrarum.HEIGHT - 180 - 40 * menuLabels.size.plus(1) + } + + + + override var width: Int = 240 + override var height: Int = 40 * menuLabels.size.plus(1) + override var handler: UIHandler? = null + override var openCloseTime = 0f + + + private val menubar = UIItemTextButtonList( + this, + menuLabels, + 240, this.height, + textAreaWidth = 240, + readFromLang = true, + activeBackCol = Color(0), + highlightBackCol = Color(0), + defaultSelection = null + ) + + init { + uiItems.add(menubar) + + + // attach listeners + menubar.buttons[3].clickOnceListener = { _, _, _ -> System.exit(0) } + } + + override fun update(delta: Float) { + menubar.update(delta) + } + + override fun render(batch: SpriteBatch) { + menubar.render(batch) + } + + override fun doOpening(delta: Float) { + + } + + override fun doClosing(delta: Float) { + + } + + override fun endOpening(delta: Float) { + + } + + override fun endClosing(delta: Float) { + + } + + override fun dispose() { + + } + + override fun mouseMoved(screenX: Int, screenY: Int): Boolean { + return super.mouseMoved(screenX, screenY) + } + + override fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean { + return super.touchDragged(screenX, screenY, pointer) + } + + override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean { + return super.touchDown(screenX, screenY, pointer, button) + } + + override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean { + return super.touchUp(screenX, screenY, pointer, button) + } + + override fun scrolled(amount: Int): Boolean { + return super.scrolled(amount) + } + + override fun keyDown(keycode: Int): Boolean { + return super.keyDown(keycode) + } + + override fun keyUp(keycode: Int): Boolean { + return super.keyUp(keycode) + } + + override fun keyTyped(character: Char): Boolean { + return super.keyTyped(character) + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/weather/WeatherMixer.kt b/src/net/torvald/terrarum/weather/WeatherMixer.kt index 63e079f9a..17f6398d3 100644 --- a/src/net/torvald/terrarum/weather/WeatherMixer.kt +++ b/src/net/torvald/terrarum/weather/WeatherMixer.kt @@ -6,8 +6,10 @@ import net.torvald.terrarum.utils.JsonFetcher import net.torvald.colourutil.* import net.torvald.random.HQRNG import net.torvald.terrarum.* +import net.torvald.terrarum.gameactors.ActorWithBody import net.torvald.terrarum.gameactors.ParticleTestRain import net.torvald.terrarum.gamecontroller.KeyToggler +import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.WorldTime import java.io.File import java.util.* @@ -31,7 +33,6 @@ object WeatherMixer { lateinit var mixedWeather: BaseModularWeather val globalLightNow = Color(0) - private val world = Terrarum.ingame!!.world // Weather indices const val WEATHER_GENERIC = "generic" @@ -68,33 +69,30 @@ object WeatherMixer { nextWeather = getRandomWeather(WEATHER_GENERIC) } - fun update(delta: Float) { + fun update(delta: Float, player: ActorWithBody) { currentWeather = weatherList[WEATHER_GENERIC]!![0] - if (Terrarum.ingame!!.player != null) { - // test rain toggled by F2 - if (KeyToggler.isOn(Input.Keys.F2)) { - val playerPos = Terrarum.ingame!!.player!!.centrePosPoint - kotlin.repeat(4) { - // 4 seems good - val rainParticle = ParticleTestRain( - playerPos.x + HQRNG().nextInt(Terrarum.WIDTH) - Terrarum.HALFW, - playerPos.y - Terrarum.HALFH - ) - Terrarum.ingame!!.addParticle(rainParticle) - } - globalLightNow.set(getGlobalLightOfTime(world.time.todaySeconds).mul(0.3f, 0.3f, 0.3f, 0.58f)) + // test rain toggled by F2 + /*if (KeyToggler.isOn(Input.Keys.F2)) { + val playerPos = player.centrePosPoint + kotlin.repeat(4) { + // 4 seems good + val rainParticle = ParticleTestRain( + playerPos.x + HQRNG().nextInt(Terrarum.WIDTH) - Terrarum.HALFW, + playerPos.y - Terrarum.HALFH + ) + Terrarum.ingame!!.addParticle(rainParticle) } + globalLightNow.set(getGlobalLightOfTime(world.time.todaySeconds).mul(0.3f, 0.3f, 0.3f, 0.58f)) + }*/ - - } } - fun render(camera: Camera) { + fun render(camera: Camera, world: GameWorld) { // we will not care for nextSkybox for now - val timeNow = Terrarum.ingame!!.world.time.todaySeconds + val timeNow = world.time.todaySeconds val skyboxColourMap = currentWeather.skyboxGradColourMap // calculate global light @@ -112,7 +110,7 @@ object WeatherMixer { Terrarum.shaderBayerSkyboxFill.setUniformMatrix("u_projTrans", camera.combined) Terrarum.shaderBayerSkyboxFill.setUniformf("topColor", topCol.r, topCol.g, topCol.b) Terrarum.shaderBayerSkyboxFill.setUniformf("bottomColor", bottomCol.r, bottomCol.g, bottomCol.b) - Terrarum.ingame!!.fullscreenQuad.render(Terrarum.shaderBayerSkyboxFill, GL20.GL_TRIANGLES) + Terrarum.fullscreenQuad.render(Terrarum.shaderBayerSkyboxFill, GL20.GL_TRIANGLES) Terrarum.shaderBayerSkyboxFill.end() } diff --git a/src/net/torvald/terrarum/worlddrawer/BlocksDrawer_old.kt b/src/net/torvald/terrarum/worlddrawer/BlocksDrawer_old.kt index 5171387a5..65ec4668a 100644 --- a/src/net/torvald/terrarum/worlddrawer/BlocksDrawer_old.kt +++ b/src/net/torvald/terrarum/worlddrawer/BlocksDrawer_old.kt @@ -27,7 +27,9 @@ import java.util.zip.GZIPInputStream * Created by minjaesong on 16-01-19. */ object BlocksDrawer { - private inline val world: GameWorld; get() = Terrarum.ingame!!.world + lateinit var world: GameWorld + + private val TILE_SIZE = FeaturesDrawer.TILE_SIZE private val TILE_SIZEF = FeaturesDrawer.TILE_SIZE.toFloat() diff --git a/src/net/torvald/terrarum/worlddrawer/FeaturesDrawer.kt b/src/net/torvald/terrarum/worlddrawer/FeaturesDrawer.kt index 5ae8feab0..86526f6f7 100644 --- a/src/net/torvald/terrarum/worlddrawer/FeaturesDrawer.kt +++ b/src/net/torvald/terrarum/worlddrawer/FeaturesDrawer.kt @@ -8,11 +8,14 @@ import net.torvald.colourutil.ColourTemp import net.torvald.terrarum.Terrarum import net.torvald.terrarum.blendMul import net.torvald.terrarum.fillRect +import net.torvald.terrarum.gameworld.GameWorld /** * Created by minjaesong on 15-12-31. */ object FeaturesDrawer { + lateinit var world: GameWorld + const val TILE_SIZE = 16 private val ENV_COLTEMP_LOWEST = 5500 @@ -36,9 +39,6 @@ object FeaturesDrawer { fun update(delta: Float) { } - fun render(batch: SpriteBatch) { - } - /** * A colour filter used to provide effect that makes whole screen look warmer/cooler, * usually targeted for the environmental temperature (desert/winterland), hence the name. @@ -52,7 +52,7 @@ object FeaturesDrawer { val colTemp_cold = colTempLinearFunc(onscreen_cold_tiles / onscreen_tiles_cap) val colTemp_warm = colTempLinearFunc(-(onscreen_warm_tiles / onscreen_tiles_cap)) colTemp = colTemp_warm + colTemp_cold - ENV_COLTEMP_NOON - val zoom = Terrarum.ingame!!.screenZoom + val zoom = Terrarum.ingame?.screenZoom ?: 1f blendMul() diff --git a/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt b/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt index 50d999047..1c32acdf3 100644 --- a/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt +++ b/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt @@ -24,7 +24,7 @@ import java.util.* // NOTE: no Float16 on this thing: 67 kB of memory footage is totally acceptable object LightmapRenderer { - private val world: GameWorld = Terrarum.ingame!!.world + lateinit var world: GameWorld // TODO if (VBO works on BlocksDrawer) THEN overscan of 256, utilise same technique in here @@ -38,9 +38,9 @@ object LightmapRenderer { // TODO resize(int, int) -aware - val LIGHTMAP_WIDTH = Terrarum.ingame!!.ZOOM_MINIMUM.inv().times(Terrarum.WIDTH) + val LIGHTMAP_WIDTH = (Terrarum.ingame?.ZOOM_MINIMUM ?: 1f).inv().times(Terrarum.WIDTH) .div(FeaturesDrawer.TILE_SIZE).ceil() + overscan_open * 2 + 3 - val LIGHTMAP_HEIGHT = Terrarum.ingame!!.ZOOM_MINIMUM.inv().times(Terrarum.HEIGHT) + val LIGHTMAP_HEIGHT = (Terrarum.ingame?.ZOOM_MINIMUM ?: 1f).inv().times(Terrarum.HEIGHT) .div(FeaturesDrawer.TILE_SIZE).ceil() + overscan_open * 2 + 3 /** @@ -48,7 +48,7 @@ object LightmapRenderer { */ // TODO utilise alpha channel to determine brightness of "glow" sprites (so that alpha channel works like UV light) private val lightmap: Array> = Array(LIGHTMAP_HEIGHT) { Array(LIGHTMAP_WIDTH, { Color(0f,0f,0f,0f) }) } // TODO framebuffer? - private val lanternMap = ArrayList(Terrarum.ingame!!.ACTORCONTAINER_INITIAL_SIZE * 4) + private val lanternMap = ArrayList((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4) private val AIR = Block.AIR @@ -178,7 +178,7 @@ object LightmapRenderer { // build noop map for (i in 0..rect_size) { val point = edgeToMaskNum(i) - val tile = Terrarum.ingame!!.world.getTileFromTerrain(point.first, point.second) ?: Block.NULL + val tile = world.getTileFromTerrain(point.first, point.second) ?: Block.NULL val isSolid = BlockCodex[tile].isSolid noop_mask.set(i, isSolid) @@ -235,25 +235,27 @@ object LightmapRenderer { private fun buildLanternmap() { lanternMap.clear() - Terrarum.ingame!!.actorContainer.forEach { it -> - if (it is Luminous && it is ActorWithPhysics) { - // put lanterns to the area the luminantBox is occupying - for (lightBox in it.lightBoxList) { - val lightBoxX = it.hitbox.startX + lightBox.startX - val lightBoxY = it.hitbox.startY + lightBox.startY - val lightBoxW = lightBox.width - val lightBoxH = lightBox.height - for (y in lightBoxY.div(TILE_SIZE).floorInt() - ..lightBoxY.plus(lightBoxH).div(TILE_SIZE).floorInt()) { - for (x in lightBoxX.div(TILE_SIZE).floorInt() - ..lightBoxX.plus(lightBoxW).div(TILE_SIZE).floorInt()) { + Terrarum.ingame?.let { + it.actorContainer.forEach { it -> + if (it is Luminous && it is ActorWithPhysics) { + // put lanterns to the area the luminantBox is occupying + for (lightBox in it.lightBoxList) { + val lightBoxX = it.hitbox.startX + lightBox.startX + val lightBoxY = it.hitbox.startY + lightBox.startY + val lightBoxW = lightBox.width + val lightBoxH = lightBox.height + for (y in lightBoxY.div(TILE_SIZE).floorInt() + ..lightBoxY.plus(lightBoxH).div(TILE_SIZE).floorInt()) { + for (x in lightBoxX.div(TILE_SIZE).floorInt() + ..lightBoxX.plus(lightBoxW).div(TILE_SIZE).floorInt()) { - val normalisedColor = it.color.cpy().mul(DIV_FLOAT) + val normalisedColor = it.color.cpy().mul(DIV_FLOAT) - lanternMap.add(Lantern(x, y, normalisedColor)) - // Q&D fix for Roundworld anomaly - lanternMap.add(Lantern(x + world.width, y, normalisedColor)) - lanternMap.add(Lantern(x - world.width, y, normalisedColor)) + lanternMap.add(Lantern(x, y, normalisedColor)) + // Q&D fix for Roundworld anomaly + lanternMap.add(Lantern(x + world.width, y, normalisedColor)) + lanternMap.add(Lantern(x - world.width, y, normalisedColor)) + } } } } @@ -270,11 +272,11 @@ object LightmapRenderer { var ambientAccumulator = Color(0f,0f,0f,0f) var lightLevelThis: Color = Color(0f,0f,0f,0f) - val thisTerrain = Terrarum.ingame!!.world.getTileFromTerrain(x, y) - val thisWall = Terrarum.ingame!!.world.getTileFromWall(x, y) + val thisTerrain = world.getTileFromTerrain(x, y) + val thisWall = world.getTileFromWall(x, y) val thisTileLuminosity = BlockCodex[thisTerrain].luminosity // already been div by four val thisTileOpacity = BlockCodex[thisTerrain].opacity // already been div by four - val sunLight = Terrarum.ingame!!.world.globalLight.cpy().mul(DIV_FLOAT) + val sunLight = world.globalLight.cpy().mul(DIV_FLOAT) // MIX TILE // open air diff --git a/src/net/torvald/terrarum/worlddrawer/WorldCamera.kt b/src/net/torvald/terrarum/worlddrawer/WorldCamera.kt index 0afcbeb44..198310474 100644 --- a/src/net/torvald/terrarum/worlddrawer/WorldCamera.kt +++ b/src/net/torvald/terrarum/worlddrawer/WorldCamera.kt @@ -2,6 +2,7 @@ package net.torvald.terrarum.worlddrawer import com.jme3.math.FastMath import net.torvald.terrarum.Terrarum +import net.torvald.terrarum.gameactors.ActorWithBody import net.torvald.terrarum.gameactors.floor import net.torvald.terrarum.gameactors.floorInt import net.torvald.terrarum.gameactors.roundInt @@ -12,7 +13,6 @@ import net.torvald.terrarum.round * Created by minjaesong on 2016-12-30. */ object WorldCamera { - private val world: GameWorld? = Terrarum.ingame?.world private val TILE_SIZE = FeaturesDrawer.TILE_SIZE var x: Int = 0 // left position @@ -32,22 +32,20 @@ object WorldCamera { val yCentre: Int get() = y + height.ushr(1) - fun update() { + fun update(world: GameWorld, player: ActorWithBody) { if (Terrarum.ingame != null) { - val player = Terrarum.ingame!!.player - - width = FastMath.ceil(Terrarum.WIDTH / Terrarum.ingame!!.screenZoom) // div, not mul - height = FastMath.ceil(Terrarum.HEIGHT / Terrarum.ingame!!.screenZoom) + width = FastMath.ceil(Terrarum.WIDTH / (Terrarum.ingame?.screenZoom ?: 1f)) // div, not mul + height = FastMath.ceil(Terrarum.HEIGHT / (Terrarum.ingame?.screenZoom ?: 1f)) // position - (WH / 2) x = (// X only: ROUNDWORLD implementation - (player?.hitbox?.centeredX?.toFloat() ?: 0f) - width / 2).floorInt() + player.hitbox.centeredX.toFloat() - width / 2).floorInt() y = (FastMath.clamp( - (player?.hitbox?.centeredY?.toFloat() ?: 0f) - height / 2, + player.hitbox.centeredY.toFloat() - height / 2, TILE_SIZE.toFloat(), - world!!.height * TILE_SIZE - height - TILE_SIZE.toFloat() - )).floorInt().clampCameraY() + world.height * TILE_SIZE - height - TILE_SIZE.toFloat() + )).floorInt().clampCameraY(world) gdxCamX = x + (width / 2f).floor() @@ -55,11 +53,11 @@ object WorldCamera { } } - private fun Int.clampCameraY(): Int { + private fun Int.clampCameraY(world: GameWorld): Int { return if (this < 0) 0 - else if (this > (world?.height ?: Terrarum.HEIGHT).times(TILE_SIZE) - Terrarum.HEIGHT) - (world?.height ?: Terrarum.HEIGHT).times(TILE_SIZE) - Terrarum.HEIGHT + else if (this > world.height.times(TILE_SIZE) - Terrarum.HEIGHT) + world.height.times(TILE_SIZE) - Terrarum.HEIGHT else this } diff --git a/src/net/torvald/terrarum/worldgenerator/FloatingIslandsPreset.kt b/src/net/torvald/terrarum/worldgenerator/FloatingIslandsPreset.kt index f7298a3dd..dee4df78c 100644 --- a/src/net/torvald/terrarum/worldgenerator/FloatingIslandsPreset.kt +++ b/src/net/torvald/terrarum/worldgenerator/FloatingIslandsPreset.kt @@ -7,6 +7,7 @@ import java.util.Random object FloatingIslandsPreset { val PRESETS = 5 + val MAX_HEIGHT = 100 // arbitrary value internal fun generatePreset(random: HQRNG): Array { val index = random.nextInt(PRESETS) diff --git a/src/net/torvald/terrarum/worldgenerator/WorldGenerator.kt b/src/net/torvald/terrarum/worldgenerator/WorldGenerator.kt index dd1017e99..7c3f624b8 100644 --- a/src/net/torvald/terrarum/worldgenerator/WorldGenerator.kt +++ b/src/net/torvald/terrarum/worldgenerator/WorldGenerator.kt @@ -8,6 +8,7 @@ import com.sudoplay.joise.Joise import com.sudoplay.joise.module.* import net.torvald.terrarum.LoadScreen import net.torvald.terrarum.Terrarum +import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.concurrent.ThreadParallel import net.torvald.terrarum.gameactors.roundInt import java.util.* @@ -64,6 +65,10 @@ object WorldGenerator { internal val TILE_MACRO_ALL = -1 + private var floatingIslandDownMax = 0 + + private var realMinimumHeight = 708 // minimum height on current setting. 705 + some headroom + fun attachMap(world: GameWorld) { this.world = world WIDTH = world.width @@ -78,6 +83,20 @@ object WorldGenerator { OCEAN_WIDTH = Math.round(OCEAN_WIDTH * widthMulFactor) SHORE_WIDTH = Math.round(SHORE_WIDTH * widthMulFactor) GLACIER_MOUNTAIN_WIDTH = Math.round(GLACIER_MOUNTAIN_WIDTH * widthMulFactor) + + + + // just a code took from island generator + floatingIslandDownMax = minimumFloatingIsleHeight * 2 + FloatingIslandsPreset.MAX_HEIGHT + + /*if (TERRAIN_AVERAGE_HEIGHT - TERRAIN_UNDULATION.div(2) -floatingIslandDownMax <= 0) { + throw RuntimeException("Terrain height is too small -- must be greater than " + + "${HEIGHT - (TERRAIN_AVERAGE_HEIGHT - TERRAIN_UNDULATION.div(2) -floatingIslandDownMax)}" + ) + }*/ + if (HEIGHT < realMinimumHeight) { + throw RuntimeException("Terrain height must be greater than $realMinimumHeight") + } } /** @@ -157,16 +176,25 @@ object WorldGenerator { generateFloatingIslands() //wire layer - for (i in 0..HEIGHT - 1) { - for (j in 0..WIDTH - 1) { - world.wireArray[i][j] = 0 - } - } + Arrays.fill(world.wireArray, 0.toByte()) + + + // determine spawn position + world.spawnY = getSpawnHeight(world.spawnX) + // Free some memories System.gc() } + fun getSpawnHeight(x: Int): Int { + var y = minimumFloatingIsleHeight * 2 + FloatingIslandsPreset.MAX_HEIGHT + while (!BlockCodex[world.getTileFromTerrain(x, y)].isSolid) { + y += 1 + } + return y + } + /* 1. Raise */ private fun noiseRidged(xStretch: Double, yStretch: Double): Joise { @@ -485,7 +513,6 @@ object WorldGenerator { val sampleY = y / SCALE_Y * 1.5 - 0.6 val map: Boolean = joise.get(sampleX, sampleY, sampleZ) == 1.0 - // FIXME joise.get(sampleX, sampleY, sampleZ) returns all zero noiseMap[y + TERRAIN_AVERAGE_HEIGHT - (TERRAIN_UNDULATION / 2)].set(x, map) } } @@ -812,7 +839,7 @@ object WorldGenerator { LoadScreen.addMessage("Flooding with lava...") for (i in HEIGHT * 14 / 15..HEIGHT - 1) { for (j in 0..WIDTH - 1) { - if (world.terrainArray[i][j].toInt() == 0) { + if (world.getTileFromTerrain(j, i) == 0) { world.setTileTerrain(j, i, Block.LAVA) } } @@ -997,25 +1024,6 @@ object WorldGenerator { return FastMath.sqrt(FastMath.pow(x1 - x2, 2f) + FastMath.pow(y2 - y1, 2f)) } - private fun circularDig(i: Int, j: Int, brushSize: Int, fillFrom: Int, fill: Int) { - val halfBrushSize = brushSize * 0.5f - - for (pointerY in 0..brushSize - 1) { - for (pointerX in 0..brushSize - 1) { - if (getDistance(j.toFloat(), i.toFloat(), j + pointerX - halfBrushSize, i + pointerY - halfBrushSize) <= FastMath.floor((brushSize / 2).toFloat()) - 1) { - if (Math.round(j + pointerX - halfBrushSize) > brushSize - && Math.round(j + pointerX - halfBrushSize) < WIDTH - brushSize - && Math.round(i + pointerY - halfBrushSize) > brushSize - && Math.round(i + pointerY - halfBrushSize) < HEIGHT - brushSize) { - if (world.terrainArray[Math.round(i + pointerY - halfBrushSize)][Math.round(j + pointerX - halfBrushSize)] == fillFrom.toByte()) { - world.terrainArray[Math.round(i + pointerY - halfBrushSize)][Math.round(j + pointerX - halfBrushSize)] = fill.toByte() - } - } - } - } - } - } - private fun clamp(x: Int, min: Int, max: Int): Int = if (x < min) min else if (x > max) max else x data class TaggedSimplexNoise(var noiseModule: SimplexNoise, var xStretch: Float, var yStretch: Float) diff --git a/work_files/DataFormats/Map data format.txt b/work_files/DataFormats/Map data format.txt index feafe90b7..b55162ef6 100644 --- a/work_files/DataFormats/Map data format.txt +++ b/work_files/DataFormats/Map data format.txt @@ -8,7 +8,7 @@ Ord Hex Description 02 4D M 03 44 D -04 01 Number of bits per tile divided by 8, only 1 is supported +04 01 Number of bytes per tile; only 1 is supported 05 Number of layers @@ -35,13 +35,17 @@ Ord Hex Description 16 Default spawn coord Y 17 Default spawn coord Y -18 Terrain tiles data (MSB) +# Layer count 1 +18 Terrain tiles data MSB -... Wall tiles data (MSB) +# Layer count 2 +... Wall tiles data MSB -... Tiles data (LSB) - 0bAAAABBBB - A: Terrain, B: Wall (0-15) +# Layer count 3 +... Terrain tiles data LSB (half size of MSB byte array) +... Wall tiles data LSB (half size of MSB byte array) +# Layer count 4 ... Wire tiles data (0-255) \ No newline at end of file diff --git a/work_files/GameDesign/WORLD_UNIVERSE_LORE.md b/work_files/GameDesign/WORLD_UNIVERSE_LORE.md index 9be890a6e..d556e9a02 100644 --- a/work_files/GameDesign/WORLD_UNIVERSE_LORE.md +++ b/work_files/GameDesign/WORLD_UNIVERSE_LORE.md @@ -16,6 +16,8 @@ Multiple maps are multiverse in this game; users don't have an access to the mul Let's be honest: when you play the Terraria bit heavily, you create multiple world to farm resources; this is cheat and you know it, which is why, in this game, you technically can but after hard working so that it'd be less of a cheat. +You can "invite" other persona to your world, from sharing things to multiplayer-on-your-own, but you need to issue "interspace ticket", which will be expensive of course. + ### New World (New Universe) The teleporter also works as "world manager"; players can create new world or delete existing ones. Lore-wise, creation and deletion is regarded as linking and unlinking.