mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
limitedly successful attempt to create a title screen
This commit is contained in:
@@ -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.
|
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
363
src/net/torvald/terrarum/TitleScreen.kt
Normal file
363
src/net/torvald/terrarum/TitleScreen.kt
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
26
src/net/torvald/terrarum/console/ExportLayerData.kt
Normal file
26
src/net/torvald/terrarum/console/ExportLayerData.kt
Normal 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")
|
||||
}
|
||||
}
|
||||
33
src/net/torvald/terrarum/console/ImportLayerData.kt
Normal file
33
src/net/torvald/terrarum/console/ImportLayerData.kt
Normal 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")
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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? {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
114
src/net/torvald/terrarum/serialise/ReadLayerData.kt
Normal file
114
src/net/torvald/terrarum/serialise/ReadLayerData.kt
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
126
src/net/torvald/terrarum/serialise/WriteLayerData.kt
Normal file
126
src/net/torvald/terrarum/serialise/WriteLayerData.kt
Normal 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)
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) }
|
||||
|
||||
|
||||
107
src/net/torvald/terrarum/ui/UIStartMenu.kt
Normal file
107
src/net/torvald/terrarum/ui/UIStartMenu.kt
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user