limitedly successful attempt to create a title screen

This commit is contained in:
minjaesong
2017-07-20 00:36:41 +09:00
parent 3727a9d27f
commit 81f0499c9d
34 changed files with 1168 additions and 410 deletions

View File

@@ -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 ##
Can't render this file because it contains an unexpected character in line 1 and column 20.

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -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<String>) {
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)
}

View File

@@ -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
}
}
}
}
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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<String>) = execute(args)

View File

@@ -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<String>) {
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")
}
}

View File

@@ -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<String>) {
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")
}
}

View File

@@ -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,

View File

@@ -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<BlockAddress, BlockDamage>()
val terrainDamages = HashMap<BlockAddress, BlockDamage>()
@@ -73,7 +74,7 @@ class GameWorld(val width: Int, val height: Int) {
* @return byte[][] terrain layer
*/
val terrainArray: Array<ByteArray>
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<ByteArray>
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<ByteArray>
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<ByteArray>
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? {

View File

@@ -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<Byte> {
internal @Volatile var data: Array<ByteArray> // 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<Byte> {
// 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<Byte> {
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)

View File

@@ -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<Byte> {
* 0110 1101 is interpreted as
* 6 for tile 0, 13 for tile 1.
*/
internal @Volatile var dataPair: Array<ByteArray>
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<Byte> {
// 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<Byte> {
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<Byte> {
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()
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}

View File

@@ -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()
)
}
}

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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)
}
}

View File

@@ -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<InventoryPair>()
inventorySortList = ArrayList<InventoryPair>()
// 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))
}

View File

@@ -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:
*
* ```
* <<some_name>>.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) {

View File

@@ -16,11 +16,11 @@ import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
class UIItemTextButtonList(
parentUI: UICanvas,
labelsList: Array<String>,
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) }

View File

@@ -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)
}
}

View File

@@ -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()
}

View File

@@ -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()

View File

@@ -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()

View File

@@ -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<Color>> = Array(LIGHTMAP_HEIGHT) { Array(LIGHTMAP_WIDTH, { Color(0f,0f,0f,0f) }) } // TODO framebuffer?
private val lanternMap = ArrayList<Lantern>(Terrarum.ingame!!.ACTORCONTAINER_INITIAL_SIZE * 4)
private val lanternMap = ArrayList<Lantern>((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

View File

@@ -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
}

View File

@@ -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<IntArray> {
val index = random.nextInt(PRESETS)

View File

@@ -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)

View File

@@ -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)
<EOF>

View File

@@ -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.