mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-06 08:38:30 +09:00
Compare commits
70 Commits
v0.3.2
...
v0.3.3-tes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1e45f1743 | ||
|
|
8dda7ac79b | ||
|
|
74b8cc20b7 | ||
|
|
f75a7dd812 | ||
|
|
b2454e4ca2 | ||
|
|
45af955488 | ||
|
|
1f39b9d448 | ||
|
|
26a4cdbce1 | ||
|
|
bf87dc04cb | ||
|
|
8535b0ce13 | ||
|
|
6e0004f165 | ||
|
|
845333f33d | ||
|
|
6988feb731 | ||
|
|
ac2c7b1148 | ||
|
|
d6145fd0da | ||
|
|
194089827c | ||
|
|
d69d032f74 | ||
|
|
a9dbea3d16 | ||
|
|
52938a4b60 | ||
|
|
a21f986f30 | ||
|
|
547158a313 | ||
|
|
0a8b5f33f4 | ||
|
|
da8d620766 | ||
|
|
7dd520393c | ||
|
|
dc83e12170 | ||
|
|
d6b2940d8f | ||
|
|
c5dfe46b76 | ||
|
|
3d3926c08b | ||
|
|
9a90bf69d4 | ||
|
|
0ed5472d8a | ||
|
|
97a7a36030 | ||
|
|
662069466a | ||
|
|
52cff00338 | ||
|
|
1a40334f8e | ||
|
|
763f512419 | ||
|
|
620a1c6956 | ||
|
|
5f4fcdba69 | ||
|
|
7a79f444b2 | ||
|
|
e4b947ce69 | ||
|
|
fdfec960ca | ||
|
|
75021ecfa2 | ||
|
|
c90ef21bfa | ||
|
|
3fce5d7e95 | ||
|
|
8db1228e70 | ||
|
|
5f7f724058 | ||
|
|
fab4179068 | ||
|
|
32803b6f18 | ||
|
|
f8f75fb7b6 | ||
|
|
9919a99032 | ||
|
|
6a43d1a5bd | ||
|
|
24c971e4b8 | ||
|
|
62f0fd7c68 | ||
|
|
3dec312989 | ||
|
|
77b51a45dd | ||
|
|
d1b4ce3404 | ||
|
|
fd7b88307c | ||
|
|
579b6b5b29 | ||
|
|
cef58f6a73 | ||
|
|
c0c98c3b80 | ||
|
|
88d844cc09 | ||
|
|
2411db17a7 | ||
|
|
53d372be38 | ||
|
|
88831051c8 | ||
|
|
87d92ecb74 | ||
|
|
6672dffdbc | ||
|
|
cd00ab4c7f | ||
|
|
014306c209 | ||
|
|
30fb57eca3 | ||
|
|
52ad8f0c46 | ||
|
|
1b08039018 |
@@ -1,26 +1,17 @@
|
||||
package net.torvald.terrarum.modulecomputers.gameactors
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import kotlin.coroutines.*
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.gameactors.AVKey
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.BlockBox
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarum.modulecomputers.ui.UIHomeComputer
|
||||
import net.torvald.tsvm.*
|
||||
import net.torvald.tsvm.peripheral.AdapterConfig
|
||||
import net.torvald.tsvm.peripheral.GraphicsAdapter
|
||||
import net.torvald.tsvm.peripheral.VMProgramRom
|
||||
import net.torvald.unicode.*
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2021-12-04.
|
||||
@@ -131,77 +122,3 @@ class FixtureHomeComputer : FixtureBase {
|
||||
}
|
||||
}
|
||||
|
||||
internal class UIHomeComputer : UICanvas(
|
||||
toggleKeyLiteral = Input.Keys.ESCAPE, // FIXME why do I have specify ESC for it to function? ESC should be work as the default key
|
||||
toggleButtonLiteral = App.getConfigInt("control_gamepad_start"),
|
||||
) {
|
||||
override var width = 640
|
||||
override var height = 480
|
||||
override var openCloseTime = 0f
|
||||
|
||||
private val drawOffX = (width - 560).div(2).toFloat()
|
||||
private val drawOffY = (height - 448).div(2).toFloat()
|
||||
|
||||
private var batch: FlippingSpriteBatch
|
||||
private var camera: OrthographicCamera
|
||||
|
||||
internal lateinit var vm: VM
|
||||
internal lateinit var fixture: FixtureHomeComputer
|
||||
|
||||
init {
|
||||
batch = FlippingSpriteBatch()
|
||||
camera = OrthographicCamera(width.toFloat(), height.toFloat())
|
||||
//val m = Matrix4()
|
||||
//m.setToOrtho2D(0f, 0f, width.toFloat(), height.toFloat())
|
||||
batch.projectionMatrix = camera.combined
|
||||
}
|
||||
|
||||
private val fbo = FrameBuffer(Pixmap.Format.RGBA8888, width, height, false)
|
||||
|
||||
private val controlHelp =
|
||||
"${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}\u3000 " +
|
||||
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_T$KEYCAP_R Terminate\u3000" +
|
||||
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_R$KEYCAP_S Reset\u3000" +
|
||||
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_R$KEYCAP_Q SysRq"
|
||||
|
||||
override fun updateUI(delta: Float) {
|
||||
}
|
||||
|
||||
override fun renderUI(otherBatch: SpriteBatch, otherCamera: Camera) {
|
||||
otherBatch.end()
|
||||
|
||||
fbo.inAction(camera, batch) {
|
||||
Gdx.gl.glClearColor(0f,0f,0f,1f)
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) // to hide the crap might be there
|
||||
|
||||
(vm.peripheralTable[1].peripheral as? GraphicsAdapter)?.let { gpu ->
|
||||
val clearCol = gpu.getBackgroundColour()
|
||||
Gdx.gl.glClearColor(clearCol.r, clearCol.g, clearCol.b, clearCol.a)
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
||||
|
||||
gpu.render(Gdx.graphics.deltaTime, batch, drawOffX, drawOffY, true, fbo) // gpu.render will internally end() the fbo then begin() again before using the batch I've fed in
|
||||
}
|
||||
}
|
||||
|
||||
otherBatch.begin()
|
||||
otherBatch.shader = null
|
||||
blendNormalStraightAlpha(otherBatch)
|
||||
otherBatch.color = Color.WHITE
|
||||
otherBatch.draw(fbo.colorBufferTexture, posX.toFloat(), posY.toFloat(), width.toFloat(), height.toFloat())
|
||||
otherBatch.color = Toolkit.Theme.COL_INACTIVE
|
||||
Toolkit.drawBoxBorder(otherBatch, posX - 1, posY - 1, width + 2, height + 2)
|
||||
|
||||
App.fontGame.draw(otherBatch, controlHelp, posX, posY + height + 4)
|
||||
}
|
||||
|
||||
override fun doOpening(delta: Float) {
|
||||
super.doOpening(delta)
|
||||
fixture.startVM()
|
||||
}
|
||||
|
||||
|
||||
override fun dispose() {
|
||||
fbo.dispose()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package net.torvald.terrarum.modulecomputers.ui
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulecomputers.gameactors.FixtureHomeComputer
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.tsvm.VM
|
||||
import net.torvald.tsvm.peripheral.GraphicsAdapter
|
||||
import net.torvald.unicode.*
|
||||
|
||||
internal class UIHomeComputer : UICanvas(
|
||||
toggleKeyLiteral = null,
|
||||
toggleButtonLiteral = "control_gamepad_start",
|
||||
) {
|
||||
override var width = 640
|
||||
override var height = 480
|
||||
override var openCloseTime = 0f
|
||||
|
||||
private val drawOffX = (width - 560).div(2).toFloat()
|
||||
private val drawOffY = (height - 448).div(2).toFloat()
|
||||
|
||||
private var batch: FlippingSpriteBatch
|
||||
private var camera: OrthographicCamera
|
||||
|
||||
internal lateinit var vm: VM
|
||||
internal lateinit var fixture: FixtureHomeComputer
|
||||
|
||||
init {
|
||||
batch = FlippingSpriteBatch()
|
||||
camera = OrthographicCamera(width.toFloat(), height.toFloat())
|
||||
//val m = Matrix4()
|
||||
//m.setToOrtho2D(0f, 0f, width.toFloat(), height.toFloat())
|
||||
batch.projectionMatrix = camera.combined
|
||||
}
|
||||
|
||||
private val fbo = FrameBuffer(Pixmap.Format.RGBA8888, width, height, false)
|
||||
|
||||
private val controlHelp =
|
||||
"${getKeycapPC(ControlPresets.getKey("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}\u3000 " +
|
||||
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_T$KEYCAP_R Terminate\u3000" +
|
||||
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_R$KEYCAP_S Reset\u3000" +
|
||||
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_R$KEYCAP_Q SysRq"
|
||||
|
||||
override fun updateUI(delta: Float) {
|
||||
}
|
||||
|
||||
override fun renderUI(otherBatch: SpriteBatch, otherCamera: Camera) {
|
||||
otherBatch.end()
|
||||
|
||||
fbo.inAction(camera, batch) {
|
||||
Gdx.gl.glClearColor(0f,0f,0f,1f)
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) // to hide the crap might be there
|
||||
|
||||
(vm.peripheralTable[1].peripheral as? GraphicsAdapter)?.let { gpu ->
|
||||
val clearCol = gpu.getBackgroundColour()
|
||||
Gdx.gl.glClearColor(clearCol.r, clearCol.g, clearCol.b, clearCol.a)
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
||||
|
||||
gpu.render(Gdx.graphics.deltaTime, batch, drawOffX, drawOffY, true, fbo) // gpu.render will internally end() the fbo then begin() again before using the batch I've fed in
|
||||
}
|
||||
}
|
||||
|
||||
otherBatch.begin()
|
||||
otherBatch.shader = null
|
||||
blendNormalStraightAlpha(otherBatch)
|
||||
otherBatch.color = Color.WHITE
|
||||
otherBatch.draw(fbo.colorBufferTexture, posX.toFloat(), posY.toFloat(), width.toFloat(), height.toFloat())
|
||||
otherBatch.color = Toolkit.Theme.COL_INACTIVE
|
||||
Toolkit.drawBoxBorder(otherBatch, posX - 1, posY - 1, width + 2, height + 2)
|
||||
|
||||
App.fontGame.draw(otherBatch, controlHelp, posX, posY + height + 4)
|
||||
}
|
||||
|
||||
override fun doOpening(delta: Float) {
|
||||
super.doOpening(delta)
|
||||
fixture.startVM()
|
||||
}
|
||||
|
||||
|
||||
override fun dispose() {
|
||||
fbo.dispose()
|
||||
}
|
||||
|
||||
}
|
||||
BIN
assets/clut/skybox.png
LFS
BIN
assets/clut/skybox.png
LFS
Binary file not shown.
@@ -8,6 +8,7 @@
|
||||
"GAME_ACTION_MOVE_VERB" : "Move",
|
||||
"GAME_ACTION_ZOOM" : "Zoom",
|
||||
"MENU_IO_AUTOSAVE": "Autosave",
|
||||
"MENU_IO_CLEAR": "Clear",
|
||||
"MENU_IO_IMPORT": "Import",
|
||||
"MENU_IO_MANUAL_SAVE": "Manual Save",
|
||||
"MENU_LABEL_COPYRIGHT": "Copyright",
|
||||
@@ -16,6 +17,7 @@
|
||||
"MENU_LABEL_IME": "IME",
|
||||
"MENU_LABEL_IME_TOGGLE": "Toggle IME",
|
||||
"MENU_LABEL_KEYBOARD_LAYOUT": "Keyboard Layout",
|
||||
"MENU_LABEL_PASTE": "Paste",
|
||||
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "Paste from Clipboard",
|
||||
"MENU_LABEL_PRESS_START_SYMBOL": "Press >",
|
||||
"MENU_LABEL_RESET" : "Reset",
|
||||
@@ -23,6 +25,7 @@
|
||||
"MENU_LABEL_STREAMING": "Livestreaming",
|
||||
"MENU_LABEL_SYSTEM_INFO": "System Info",
|
||||
"MENU_MODULES" : "Modules",
|
||||
"MENU_OPTIONS_ATLAS_TEXTURE_SIZE": "Atlas Texture Size",
|
||||
"MENU_OPTIONS_AUTOSAVE": "Autosave",
|
||||
"MENU_OPTIONS_BLUR": "Blur",
|
||||
"MENU_OPTIONS_DEBUG_CONSOLE": "Debug Console",
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"GAME_ACTION_MOVE_VERB" : "이동하기",
|
||||
"GAME_ACTION_ZOOM" : "확대·축소",
|
||||
"MENU_IO_AUTOSAVE": "자동 저장",
|
||||
"MENU_IO_CLEAR": "지우기",
|
||||
"MENU_IO_IMPORT": "가져오기",
|
||||
"MENU_IO_MANUAL_SAVE": "수동 저장",
|
||||
"MENU_LABEL_COPYRIGHT": "저작권",
|
||||
@@ -16,6 +17,7 @@
|
||||
"MENU_LABEL_IME": "입력기",
|
||||
"MENU_LABEL_IME_TOGGLE": "입력기 켜고 끄기",
|
||||
"MENU_LABEL_KEYBOARD_LAYOUT": "자판 배열",
|
||||
"MENU_LABEL_PASTE": "붙여넣기",
|
||||
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "복사한 텍스트 붙여넣기",
|
||||
"MENU_LABEL_PRESS_START_SYMBOL": ">을 누르세요",
|
||||
"MENU_LABEL_RESET" : "재설정",
|
||||
@@ -23,6 +25,7 @@
|
||||
"MENU_LABEL_STREAMING": "실시간 방송",
|
||||
"MENU_LABEL_SYSTEM_INFO": "시스템 정보",
|
||||
"MENU_MODULES" : "모듈",
|
||||
"MENU_OPTIONS_ATLAS_TEXTURE_SIZE": "아틀라스 텍스처 크기",
|
||||
"MENU_OPTIONS_AUTOSAVE": "자동 저장",
|
||||
"MENU_OPTIONS_BLUR": "흐림",
|
||||
"MENU_OPTIONS_DEBUG_CONSOLE": "디버그 콘솔",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"id";"drop";"spawn";"name";"shdr";"shdg";"shdb";"shduv";"str";"dsty";"mate";"solid";"wall";"grav";"dlfn";"fv";"fr";"lumr";"lumg";"lumb";"lumuv";"colour";"vscs";"refl";"tags"
|
||||
"0";"0";"0";"BLOCK_AIR";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";""
|
||||
"0";"0";"0";"BLOCK_AIR";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"INCONSEQUENTIAL"
|
||||
"16";"17";"17";"BLOCK_STONE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ROCK,NATURAL"
|
||||
"17";"17";"17";"BLOCK_STONE_QUARRIED";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ROCK"
|
||||
"18";"18";"18";"BLOCK_STONE_TILE_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.18";"STONE"
|
||||
@@ -188,6 +188,7 @@
|
||||
## Some tags are reserved for internal use, which are:
|
||||
## - INTERNAL: denotes that the tile is internal-use. Will not be rendered unless debug window is on.
|
||||
## - DORENDER: this internal tile must go through the standard-issue tile drawing routine.
|
||||
## - INCONSEQUENTIAL: denotes that this tile can be overwritten without dropping it. Usually used with flower tiles.
|
||||
#
|
||||
#
|
||||
## References ##
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 179 and column 37.
|
@@ -32,4 +32,5 @@ Teleport
|
||||
ToggleNoClip
|
||||
Zoom
|
||||
DynToStatic
|
||||
DebugFillInventory
|
||||
DebugFillInventory
|
||||
Uuid
|
||||
|
@@ -8,6 +8,7 @@ id;classname
|
||||
8;net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalEmitter
|
||||
9;net.torvald.terrarum.modulebasegame.gameitems.WireCutterAll
|
||||
10;net.torvald.terrarum.modulebasegame.gameitems.ItemTypewriter
|
||||
11;net.torvald.terrarum.modulebasegame.gameitems.ItemWallCalendar
|
||||
|
||||
256;net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorOak
|
||||
257;net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorEbony
|
||||
|
||||
|
34
assets/mods/basegame/locales/en/calendar.json
Normal file
34
assets/mods/basegame/locales/en/calendar.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"MENU_CALENDAR_CALENDAR": "Calendar",
|
||||
"MENU_CALENDAR_EVENTS": "Events",
|
||||
"MENU_CALENDAR_ADD_NEW_EVENT": "Add New Event",
|
||||
"CONTEXT_CALENDAR_SEASON_SPRING": "Spring",
|
||||
"CONTEXT_CALENDAR_SEASON_SUMMER": "Summer",
|
||||
"CONTEXT_CALENDAR_SEASON_AUTUMN": "Autumn",
|
||||
"CONTEXT_CALENDAR_SEASON_WINTER": "Winter",
|
||||
"CONTEXT_CALENDAR_SEASON_SPRI": "Spri",
|
||||
"CONTEXT_CALENDAR_SEASON_SUMM": "Summ",
|
||||
"CONTEXT_CALENDAR_SEASON_AUTM": "Autm",
|
||||
"CONTEXT_CALENDAR_SEASON_WINT": "Wint",
|
||||
"CONTEXT_CALENDAR_DATE_FORMAT_Y": "Year {0}",
|
||||
"CONTEXT_CALENDAR_DATE_FORMAT_YMD": "Year {0} {1} {2}",
|
||||
"CONTEXT_CALENDAR_DATE_FORMAT_YMD_DDD": "Year {0} {1} {2} {3}",
|
||||
|
||||
"CONTEXT_CALENDAR_DAY_MONDAG_DNT": "Mondag",
|
||||
"CONTEXT_CALENDAR_DAY_TYSDAG_DNT": "Tysdag",
|
||||
"CONTEXT_CALENDAR_DAY_MIDTVEKE_DNT": "Midtveke",
|
||||
"CONTEXT_CALENDAR_DAY_TORSDAG_DNT": "Torsdag",
|
||||
"CONTEXT_CALENDAR_DAY_FREDAG_DNT": "Fredag",
|
||||
"CONTEXT_CALENDAR_DAY_LAURDAG_DNT": "Laurdag",
|
||||
"CONTEXT_CALENDAR_DAY_SUNDAG_DNT": "Sundag",
|
||||
"CONTEXT_CALENDAR_DAY_VERDDAG_DNT": "Verddag",
|
||||
"CONTEXT_CALENDAR_DAY_MON_DNT": "Mon",
|
||||
"CONTEXT_CALENDAR_DAY_TYS_DNT": "Tys",
|
||||
"CONTEXT_CALENDAR_DAY_MID_DNT": "Mid",
|
||||
"CONTEXT_CALENDAR_DAY_TOR_DNT": "Tor",
|
||||
"CONTEXT_CALENDAR_DAY_FRE_DNT": "Fre",
|
||||
"CONTEXT_CALENDAR_DAY_LAU_DNT": "Lau",
|
||||
"CONTEXT_CALENDAR_DAY_SUN_DNT": "Sun",
|
||||
"CONTEXT_CALENDAR_DAY_VER_DNT": "Ver",
|
||||
"CONTEXT_CALENDAR_DATE_FORMAT_YMD_SHORT_DNT": "ɣ{0}-{1}-{2}"
|
||||
}
|
||||
@@ -1,23 +1,24 @@
|
||||
{
|
||||
"CONTEXT_GENERATOR_SEED": "Seed",
|
||||
"CONTEXT_ITEM_MAP": "Map",
|
||||
"CONTEXT_ITEM_TOOL_PLURAL": "Tools",
|
||||
"CONTEXT_PLACE_COORDINATE": "Coordinate",
|
||||
"CONTEXT_WORLD_COUNT": "Worlds: ",
|
||||
"CONTEXT_WORLD_NEW": "New World",
|
||||
"MENU_LABEL_DELETE_WORLD": "Delete World",
|
||||
"CONTEXT_WORLD_COUNT": "Worlds: ",
|
||||
"GAME_INVENTORY_INGREDIENTS": "Ingredients",
|
||||
"GAME_INVENTORY_POTIONS": "Potions",
|
||||
"GAME_INVENTORY_BLOCKS": "Blocks",
|
||||
"GAME_INVENTORY_WALLS": "Walls",
|
||||
"CONTEXT_ITEM_TOOL_PLURAL": "Tools",
|
||||
"GAME_INVENTORY_FAVORITES": "Favorites",
|
||||
"GAME_INVENTORY_REGISTER": "Register",
|
||||
"CONTEXT_ITEM_MAP": "Map",
|
||||
"MENU_LABEL_MENU": "Menu",
|
||||
"CONTEXT_GENERATOR_SEED": "Seed",
|
||||
"MENU_LABEL_PREV_SAVES": "Previous Saves",
|
||||
"MENU_LABEL_RENAME": "Rename",
|
||||
"GAME_ACTION_CRAFT": "Craft",
|
||||
"GAME_ACTION_GRAPPLE": "Grapple",
|
||||
"GAME_ACTION_QUICKSEL": "Quick Select",
|
||||
"GAME_ACTION_CRAFT": "Craft",
|
||||
"GAME_CRAFTING": "Crafting",
|
||||
"GAME_CRAFTABLE_ITEMS": "Craftable Items",
|
||||
"MENU_LABEL_RENAME": "Rename",
|
||||
"GAME_ACTION_TELEPORT": "Teleport",
|
||||
"CONTEXT_PLACE_COORDINATE": "Coordinate"
|
||||
"GAME_CRAFTABLE_ITEMS": "Craftable Items",
|
||||
"GAME_CRAFTING": "Crafting",
|
||||
"GAME_INVENTORY_BLOCKS": "Blocks",
|
||||
"GAME_INVENTORY_FAVORITES": "Favorites",
|
||||
"GAME_INVENTORY_INGREDIENTS": "Ingredients",
|
||||
"GAME_INVENTORY_POTIONS": "Potions",
|
||||
"GAME_INVENTORY_REGISTER": "Register",
|
||||
"GAME_INVENTORY_WALLS": "Walls"
|
||||
}
|
||||
@@ -1,18 +1,20 @@
|
||||
{
|
||||
"BLOCK_STONE_DEEP": "Deepstone",
|
||||
"BLOCK_SCAFFOLDING_NORMAL": "Scaffolding",
|
||||
"BLOCK_STONE_MARBLE": "Marble",
|
||||
|
||||
"ITEM_CALENDAR": "Calendar",
|
||||
"ITEM_LOGIC_SIGNAL_EMITTER": "Logic Signal Emitter",
|
||||
"ITEM_STORAGE_CHEST": "Storage Chest",
|
||||
"ITEM_TIKI_TORCH": "Tiki Torch",
|
||||
"ITEM_TYPEWRITER": "Typewriter",
|
||||
"ITEM_WIRE": "Wire",
|
||||
"ITEM_WIRE_CUTTER": "Wire Cutter",
|
||||
|
||||
"ACTORBLOCK_ALLOW_MOVE_DOWN": "Urist Arôlcustith",
|
||||
"ACTORBLOCK_FULL_COLLISION": "Urist Berdanrifot",
|
||||
"ACTORBLOCK_NO_COLLISION": "Urist Zafal",
|
||||
"ACTORBLOCK_NO_PASS_RIGHT": "Urist McPassLeft",
|
||||
"ACTORBLOCK_NO_PASS_LEFT": "Urist McPassRight",
|
||||
"ACTORBLOCK_TILING_PLACEHOLDER": "Urist Berdanurdim",
|
||||
|
||||
"BLOCK_STONE_DEEP": "Deepstone",
|
||||
"BLOCK_SCAFFOLDING_NORMAL": "Scaffolding",
|
||||
"BLOCK_STONE_MARBLE": "Marble",
|
||||
|
||||
"ITEM_STORAGE_CHEST": "Storage Chest",
|
||||
"ITEM_WIRE": "Wire",
|
||||
"ITEM_WIRE_CUTTER": "Wire Cutter",
|
||||
"ITEM_LOGIC_SIGNAL_EMITTER": "Logic Signal Emitter",
|
||||
"ITEM_TIKI_TORCH": "Tiki Torch"
|
||||
"ACTORBLOCK_TILING_PLACEHOLDER": "Urist Berdanurdim"
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "This is a world currently playing."
|
||||
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "This is a world currently playing.",
|
||||
"CONTEXT_IMPORT_AVATAR_INSTRUCTION_1": "Copy the Avatar Code into the clipboard, then hit the Paste button below.",
|
||||
"CONTEXT_IMPORT_AVATAR_INSTRUCTION_2": ""
|
||||
}
|
||||
16
assets/mods/basegame/locales/koKR/calendar.json
Normal file
16
assets/mods/basegame/locales/koKR/calendar.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"MENU_CALENDAR_CALENDAR": "달력",
|
||||
"MENU_CALENDAR_EVENTS": "일정",
|
||||
"MENU_CALENDAR_ADD_NEW_EVENT": "새 일정 추가",
|
||||
"CONTEXT_CALENDAR_SEASON_SPRING": "봄",
|
||||
"CONTEXT_CALENDAR_SEASON_SUMMER": "여름",
|
||||
"CONTEXT_CALENDAR_SEASON_AUTUMN": "가을",
|
||||
"CONTEXT_CALENDAR_SEASON_WINTER": "겨울",
|
||||
"CONTEXT_CALENDAR_SEASON_SPRI": "봄",
|
||||
"CONTEXT_CALENDAR_SEASON_SUMM": "여름",
|
||||
"CONTEXT_CALENDAR_SEASON_AUTM": "가을",
|
||||
"CONTEXT_CALENDAR_SEASON_WINT": "겨울",
|
||||
"CONTEXT_CALENDAR_DATE_FORMAT_Y": "{0}년",
|
||||
"CONTEXT_CALENDAR_DATE_FORMAT_YMD": "{0}년 {1} {2}일",
|
||||
"CONTEXT_CALENDAR_DATE_FORMAT_YMD_DDD": "{0}년 {1} {2}일 {3}"
|
||||
}
|
||||
@@ -1,24 +1,25 @@
|
||||
{
|
||||
"CONTEXT_GENERATOR_SEED": "시드",
|
||||
"CONTEXT_ITEM_MAP": "지도",
|
||||
"CONTEXT_ITEM_TOOL_PLURAL": "도구",
|
||||
"CONTEXT_PLACE_COORDINATE": "좌표",
|
||||
"CONTEXT_WORLD_COUNT": "새계: ",
|
||||
"CONTEXT_WORLD_NEW": "새 세계",
|
||||
"MENU_LABEL_DELETE_WORLD": "새계 삭제",
|
||||
"CONTEXT_WORLD_COUNT": "새계: ",
|
||||
"MENU_MONITOR_CALI_TITLE": "모니터 확인",
|
||||
"GAME_INVENTORY_INGREDIENTS": "재료",
|
||||
"GAME_INVENTORY_POTIONS": "물약",
|
||||
"GAME_INVENTORY_BLOCKS": "블록",
|
||||
"GAME_INVENTORY_WALLS": "벽지",
|
||||
"CONTEXT_ITEM_TOOL_PLURAL": "도구",
|
||||
"GAME_INVENTORY_FAVORITES": "즐겨찾기",
|
||||
"GAME_INVENTORY_REGISTER": "등록하기",
|
||||
"MENU_LABEL_MENU": "메뉴",
|
||||
"CONTEXT_ITEM_MAP": "지도",
|
||||
"CONTEXT_GENERATOR_SEED": "시드",
|
||||
"MENU_LABEL_PREV_SAVES": "이전 세이브",
|
||||
"MENU_LABEL_RENAME": "이름 바꾸기",
|
||||
"MENU_MONITOR_CALI_TITLE": "모니터 확인",
|
||||
"GAME_ACTION_CRAFT": "제작하기",
|
||||
"GAME_ACTION_GRAPPLE": "매달리기",
|
||||
"GAME_ACTION_QUICKSEL": "빠른 선택",
|
||||
"GAME_ACTION_CRAFT": "제작하기",
|
||||
"GAME_CRAFTING": "제작",
|
||||
"GAME_CRAFTABLE_ITEMS": "제작 가능한 아이템",
|
||||
"MENU_LABEL_RENAME": "이름 바꾸기",
|
||||
"GAME_ACTION_TELEPORT": "텔레포트하기",
|
||||
"CONTEXT_PLACE_COORDINATE": "좌표"
|
||||
"GAME_CRAFTABLE_ITEMS": "제작 가능한 아이템",
|
||||
"GAME_CRAFTING": "제작",
|
||||
"GAME_INVENTORY_BLOCKS": "블록",
|
||||
"GAME_INVENTORY_FAVORITES": "즐겨찾기",
|
||||
"GAME_INVENTORY_INGREDIENTS": "재료",
|
||||
"GAME_INVENTORY_POTIONS": "물약",
|
||||
"GAME_INVENTORY_REGISTER": "등록하기",
|
||||
"GAME_INVENTORY_WALLS": "벽지"
|
||||
}
|
||||
@@ -3,9 +3,11 @@
|
||||
"BLOCK_SCAFFOLDING_NORMAL": "발판",
|
||||
"BLOCK_STONE_MARBLE": "대리석",
|
||||
|
||||
"ITEM_STORAGE_CHEST": "보관상자",
|
||||
"ITEM_WIRE": "전선",
|
||||
"ITEM_WIRE_CUTTER": "전선 절단기",
|
||||
"ITEM_CALENDAR": "달력",
|
||||
"ITEM_LOGIC_SIGNAL_EMITTER": "신호발생기",
|
||||
"ITEM_TIKI_TORCH": "티키 토치"
|
||||
"ITEM_STORAGE_CHEST": "보관상자",
|
||||
"ITEM_TIKI_TORCH": "티키 토치",
|
||||
"ITEM_TYPEWRITER": "타자기",
|
||||
"ITEM_WIRE": "전선",
|
||||
"ITEM_WIRE_CUTTER": "전선 절단기"
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "현재 플레이 중인 월드입니다."
|
||||
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "현재 플레이 중인 월드입니다.",
|
||||
"CONTEXT_IMPORT_AVATAR_INSTRUCTION_1": "아바타 코드를 클립보드에 복사한 다음, 아래의 붙여넣기 버튼을 눌러주세요.",
|
||||
"CONTEXT_IMPORT_AVATAR_INSTRUCTION_2": ""
|
||||
}
|
||||
BIN
assets/mods/basegame/sprites/fixtures/calendar.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/calendar.tga
LFS
Normal file
Binary file not shown.
@@ -2,7 +2,21 @@
|
||||
"skyboxGradColourMap": "generic_skybox.tga",
|
||||
"daylightClut": "clut_daylight.tga",
|
||||
"classification": "generic",
|
||||
"extraImages": [
|
||||
|
||||
]
|
||||
"cloudChance": 250,
|
||||
"cloudGamma": [0.48, 1.8],
|
||||
"cloudGammaVariance": [0.1, 0.1],
|
||||
"windSpeed": 10.25,
|
||||
"windSpeedVariance": 1.0,
|
||||
"clouds": {
|
||||
"cumulonimbus": {
|
||||
"filename": "cloud_large.png", "tw": 2048, "th": 1024, "probability": 0.2,
|
||||
"baseScale": 2.0, "scaleVariance": 0.3333333,
|
||||
"altLow": 80, "altHigh": 120
|
||||
},
|
||||
"cumulus": {
|
||||
"filename": "cloud_normal.png", "tw": 1024, "th": 512, "probability": 1.0,
|
||||
"baseScale": 1.0, "scaleVariance": 0.6,
|
||||
"altLow": 80, "altHigh": 800
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"globalLight": "generic_light.tga",
|
||||
"skyboxGradColourMap": "generic_skybox.tga",
|
||||
"classification": "genericrain",
|
||||
"extraImages": [
|
||||
"raindrop.tga"
|
||||
],
|
||||
"mixFrom": "__CURRENTWEATHER",
|
||||
"mixPercentage": 80.0
|
||||
}
|
||||
27
assets/mods/basegame/weathers/WeatherOvercast.json
Normal file
27
assets/mods/basegame/weathers/WeatherOvercast.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"skyboxGradColourMap": "generic_skybox.tga",
|
||||
"daylightClut": "clut_daylight.tga",
|
||||
"classification": "overcast",
|
||||
"cloudChance": 300,
|
||||
"cloudGamma": [2.2, 2.0],
|
||||
"cloudGammaVariance": [0.1, 0.1],
|
||||
"windSpeed": 10.45,
|
||||
"windSpeedVariance": 1.0,
|
||||
"clouds": {
|
||||
"cumulus": {
|
||||
"filename": "cloud_normal.png", "tw": 1024, "th": 512, "probability": 0.1,
|
||||
"baseScale": 0.8, "scaleVariance": 0.6,
|
||||
"altLow": 80, "altHigh": 800
|
||||
},
|
||||
"cumulonimbus": {
|
||||
"filename": "cloud_large.png", "tw": 2048, "th": 1024, "probability": 0.4,
|
||||
"baseScale": 2.0, "scaleVariance": 0.3333333,
|
||||
"altLow": 90, "altHigh": 120
|
||||
},
|
||||
"nimbostratus": {
|
||||
"filename": "cloud_wide.png", "tw": 4096, "th": 1024, "probability": 1.0,
|
||||
"baseScale": 4.0, "scaleVariance": 0.1,
|
||||
"altLow": 100, "altHigh": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
assets/mods/basegame/weathers/cloud_large.kra
LFS
Normal file
BIN
assets/mods/basegame/weathers/cloud_large.kra
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/weathers/cloud_large.png
LFS
Normal file
BIN
assets/mods/basegame/weathers/cloud_large.png
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/weathers/cloud_normal.kra
LFS
Normal file
BIN
assets/mods/basegame/weathers/cloud_normal.kra
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/weathers/cloud_normal.png
LFS
Normal file
BIN
assets/mods/basegame/weathers/cloud_normal.png
LFS
Normal file
Binary file not shown.
26
assets/mods/basegame/weathers/cloud_texture_instruction.md
Normal file
26
assets/mods/basegame/weathers/cloud_texture_instruction.md
Normal file
@@ -0,0 +1,26 @@
|
||||
## actually blending
|
||||
1. On Krita, load the cloudmap
|
||||
2. Select and isolate suitable piece of the cloud
|
||||
3. With liquefying brush, make the bottom flat
|
||||
4. On new tab, load the solidmap
|
||||
5. Resize the solidmap to 1024x1024
|
||||
6. Rotate the solidmap by 30 deg or so
|
||||
7. Overlay the processed solidmap to the cloudmap, opacity=30%
|
||||
8. With airbrush tool, manually add the shade (see cloud_normal.kra to get the gist of it)
|
||||
|
||||
### cloudmap
|
||||
1. On GIMP, prepare 4096x4096 canvas
|
||||
2. Create Simplex Noise with following parameters:
|
||||
- Scale: arbitrary (0.05 - 0.2)
|
||||
- Iterations: MAX
|
||||
- Seed: anything but 0
|
||||
|
||||
### solidmap
|
||||
1. On GIMP, prepare 4096x4096 canvas
|
||||
2. Create Solid Noise with following parameters:
|
||||
- XY Size: 16.0
|
||||
- Detail: MAX
|
||||
- Tileable: check
|
||||
- Turbulent: check
|
||||
- Seed: anything but 0
|
||||
|
||||
BIN
assets/mods/basegame/weathers/cloud_wide.kra
LFS
Normal file
BIN
assets/mods/basegame/weathers/cloud_wide.kra
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/weathers/cloud_wide.png
LFS
Normal file
BIN
assets/mods/basegame/weathers/cloud_wide.png
LFS
Normal file
Binary file not shown.
@@ -3,7 +3,8 @@ if (( $EUID == 0 )); then echo "The build process is not meant to be run with ro
|
||||
|
||||
cd "${0%/*}"
|
||||
SRCFILES="terrarummac_arm"
|
||||
DESTDIR="out/TerrarumMac.arm.app"
|
||||
APPDIR="./TerrarumMac.arm.app"
|
||||
DESTDIR="out/$APPDIR"
|
||||
RUNTIME="runtime-osx-arm"
|
||||
|
||||
if [ ! -d "../assets_release" ]; then
|
||||
@@ -34,4 +35,8 @@ cp -r "../assets_release" $DESTDIR/Contents/MacOS/
|
||||
mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets
|
||||
cp "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/out/
|
||||
|
||||
cd "out"
|
||||
rm $APPDIR.zip
|
||||
7z a -tzip $APPDIR.zip $APPDIR
|
||||
|
||||
echo "Build successful: $DESTDIR"
|
||||
|
||||
@@ -3,7 +3,8 @@ if (( $EUID == 0 )); then echo "The build process is not meant to be run with ro
|
||||
|
||||
cd "${0%/*}"
|
||||
SRCFILES="terrarummac_x86"
|
||||
DESTDIR="out/TerrarumMac.x86.app"
|
||||
APPDIR="./TerrarumMac.x86.app"
|
||||
DESTDIR="out/$APPDIR"
|
||||
RUNTIME="runtime-osx-x86"
|
||||
|
||||
if [ ! -d "../assets_release" ]; then
|
||||
@@ -34,4 +35,8 @@ cp -r "../assets_release" $DESTDIR/Contents/MacOS/
|
||||
mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets
|
||||
cp "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/out/
|
||||
|
||||
cd "out"
|
||||
rm $APPDIR.zip
|
||||
7z a -tzip $APPDIR.zip $APPDIR
|
||||
|
||||
echo "Build successful: $DESTDIR"
|
||||
|
||||
@@ -35,6 +35,7 @@ mv $DESTDIR/assets_release $DESTDIR/assets
|
||||
cp "../out/TerrarumBuild.jar" $DESTDIR/out/
|
||||
|
||||
# Temporary solution: zip everything
|
||||
rm "out/TerrarumWindows.x86.zip"
|
||||
zip -r -9 -l "out/TerrarumWindows.x86.zip" $DESTDIR
|
||||
rm -rf $DESTDIR || true
|
||||
echo "Build successful: $DESTDIR"
|
||||
|
||||
28
buildapp/make_assets_release.sh
Executable file
28
buildapp/make_assets_release.sh
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
if (( $EUID == 0 )); then echo "The build process is not meant to be run with root privilege, exiting now." >&2; exit 1; fi
|
||||
|
||||
cd "${0%/*}"
|
||||
DESTDIR="../assets_release"
|
||||
|
||||
rm -r $DESTDIR
|
||||
cp -r "../assets" $DESTDIR
|
||||
|
||||
rm $DESTDIR/loopey.wav
|
||||
rm $DESTDIR/ktGrepExample.kts
|
||||
rm $DESTDIR/batchtest.txt
|
||||
rm $DESTDIR/test_texture.tga
|
||||
rm $DESTDIR/worldbacktest.tga
|
||||
rm -r $DESTDIR/books
|
||||
rm $DESTDIR/clut/skybox.tga
|
||||
rm $DESTDIR/graphics/*.bat
|
||||
rm $DESTDIR/keylayout/*.not_ime
|
||||
rm $DESTDIR/mods/basegame/blocks/*.gz
|
||||
rm $DESTDIR/mods/basegame/blocks/*.txt
|
||||
rm $DESTDIR/mods/basegame/weathers/*.txt
|
||||
rm $DESTDIR/mods/basegame/weathers/*.md
|
||||
rm $DESTDIR/mods/basegame/weathers/*.kra
|
||||
rm -r $DESTDIR/mods/basegame/sounds
|
||||
rm -r $DESTDIR/mods/dwarventech
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <tchar.h>
|
||||
|
||||
int main() {
|
||||
return system(".\\out\\runtime-windows-x86\\bin\\Terrarum.exe -jar .\\out\\TerrarumBuild.jar");
|
||||
|
||||
ShellExecute(NULL, "open", "\".\\out\\runtime-windows-x86\\bin\\Terrarum.exe\"", "-jar \".\\out\\TerrarumBuild.jar\"", NULL, SW_HIDE);
|
||||
return 0;
|
||||
|
||||
//return system(".\\out\\runtime-windows-x86\\bin\\Terrarum.exe -jar .\\out\\TerrarumBuild.jar");
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.badlogic.gdx.graphics.glutils;
|
||||
|
||||
import com.badlogic.gdx.Application;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.GL30;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException;
|
||||
import net.torvald.terrarum.App;
|
||||
|
||||
// typealias Float16FrameBuffer = FloatFrameBuffer
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-08-16.
|
||||
*/
|
||||
public class Float16FrameBuffer extends FrameBuffer {
|
||||
|
||||
Float16FrameBuffer () {
|
||||
}
|
||||
|
||||
/** Creates a GLFrameBuffer from the specifications provided by bufferBuilder
|
||||
*
|
||||
* @param bufferBuilder **/
|
||||
protected Float16FrameBuffer (GLFrameBufferBuilder<? extends GLFrameBuffer<Texture>> bufferBuilder) {
|
||||
super(bufferBuilder);
|
||||
}
|
||||
|
||||
/** Creates a new FrameBuffer with a float backing texture, having the given dimensions and potentially a depth buffer
|
||||
* attached.
|
||||
*
|
||||
* @param width the width of the framebuffer in pixels
|
||||
* @param height the height of the framebuffer in pixels
|
||||
* @param hasDepth whether to attach a depth buffer
|
||||
* @throws GdxRuntimeException in case the FrameBuffer could not be created */
|
||||
public Float16FrameBuffer (int width, int height, boolean hasDepth) {
|
||||
if (App.isAppleM) { // disable float framebuffer for Apple M chips
|
||||
FrameBufferBuilder bufferBuilder = new FrameBufferBuilder(width, height);
|
||||
bufferBuilder.addColorTextureAttachment(GL20.GL_RGBA, GL20.GL_RGBA, GL20.GL_UNSIGNED_SHORT); // but 16bpp int works perfectly?!
|
||||
if (hasDepth) bufferBuilder.addBasicDepthRenderBuffer();
|
||||
this.bufferBuilder = bufferBuilder;
|
||||
}
|
||||
else {
|
||||
FloatFrameBufferBuilder bufferBuilder = new FloatFrameBufferBuilder(width, height);
|
||||
bufferBuilder.addFloatAttachment(GL30.GL_RGBA16F, GL30.GL_RGBA, GL30.GL_FLOAT, false); // FIXME sporadic black screen on GL_RGBA16F? or maybe it was Plasma bugging out?
|
||||
if (hasDepth) bufferBuilder.addBasicDepthRenderBuffer();
|
||||
this.bufferBuilder = bufferBuilder;
|
||||
}
|
||||
|
||||
build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Texture createTexture (FrameBufferTextureAttachmentSpec attachmentSpec) {
|
||||
if (App.isAppleM) {
|
||||
GLOnlyTextureData data = new GLOnlyTextureData(bufferBuilder.width, bufferBuilder.height, 0, attachmentSpec.internalFormat,
|
||||
attachmentSpec.format, attachmentSpec.type);
|
||||
Texture result = new Texture(data);
|
||||
result.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
|
||||
result.setWrap(Texture.TextureWrap.ClampToEdge, Texture.TextureWrap.ClampToEdge);
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
FloatTextureData data = new FloatTextureData(bufferBuilder.width, bufferBuilder.height, attachmentSpec.internalFormat,
|
||||
attachmentSpec.format, attachmentSpec.type, attachmentSpec.isGpuOnly);
|
||||
Texture result = new Texture(data);
|
||||
result.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
|
||||
result.setWrap(Texture.TextureWrap.ClampToEdge, Texture.TextureWrap.ClampToEdge);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -248,6 +248,10 @@ final public class FastMath {
|
||||
return interpolateCatmullRom(u, 0.5f, p0, p1, p2, p3);
|
||||
}
|
||||
|
||||
public static float interpolateCatmullRom(float u, float[] ps) {
|
||||
return interpolateCatmullRom(u, 0.5f, ps[0], ps[1], ps[2], ps[3]);
|
||||
}
|
||||
|
||||
/**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
|
||||
* here is the interpolation matrix
|
||||
* m = [ 0.0 1.0 0.0 0.0 ]
|
||||
@@ -331,8 +335,7 @@ final public class FastMath {
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
public static float interpolateHermite(float scale, float p0, float p1, float p2, float p3) {
|
||||
/*public static float interpolateHermite(float scale, float p0, float p1, float p2, float p3) {
|
||||
// return interpolateHermite(scale, p0, p1, p2, p3, 0f, 0f);
|
||||
float mu2 = scale * scale;
|
||||
float mu3 = mu2 * scale;
|
||||
@@ -350,7 +353,7 @@ final public class FastMath {
|
||||
float a3 = -2*mu3 + 3*mu2 + 0;
|
||||
|
||||
return a0*p1 + a1*m0 + a2*m1 + a3*p2;
|
||||
}
|
||||
}*/
|
||||
//public static float interpolateHermite(float scale, float p0, float p1, float p2, float p3, float tension, float bias) {}
|
||||
|
||||
|
||||
|
||||
@@ -192,6 +192,16 @@ fun CIEXYZ.toColorRaw(): Color {
|
||||
return Color(rgb.r, rgb.g, rgb.b, rgb.alpha)
|
||||
}
|
||||
|
||||
fun CIEXYZ.toYXY(): CIEYXY {
|
||||
val dot = this.X + this.Y + this.Z
|
||||
return CIEYXY(
|
||||
this.Y,
|
||||
this.X / dot,
|
||||
this.Y / dot,
|
||||
this.alpha
|
||||
)
|
||||
}
|
||||
|
||||
fun CIEYXY.toXYZ(): CIEXYZ {
|
||||
return CIEXYZ(x * yy / y, yy, (1f - x - y) * yy / y)
|
||||
}
|
||||
|
||||
@@ -12,16 +12,14 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.unicode.EMDASH
|
||||
import net.torvald.colourutil.*
|
||||
import net.torvald.parametricsky.datasets.DatasetCIEXYZ
|
||||
import net.torvald.parametricsky.datasets.DatasetRGB
|
||||
import net.torvald.parametricsky.datasets.DatasetSpectral
|
||||
import net.torvald.terrarum.abs
|
||||
import net.torvald.terrarum.clut.Skybox
|
||||
import net.torvald.terrarum.clut.Skybox.coerceInSmoothly
|
||||
import net.torvald.terrarum.clut.Skybox.mapCircle
|
||||
import net.torvald.terrarum.inUse
|
||||
import net.torvald.terrarum.modulebasegame.worldgenerator.HALF_PI
|
||||
import net.torvald.terrarum.modulebasegame.worldgenerator.TWO_PI
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Dimension
|
||||
import java.awt.FlowLayout
|
||||
import java.awt.GridLayout
|
||||
import java.lang.Math.pow
|
||||
import javax.swing.*
|
||||
import kotlin.math.*
|
||||
@@ -94,7 +92,16 @@ class Application(val WIDTH: Int, val HEIGHT: Int) : Game() {
|
||||
if (turbidity <= 0) throw IllegalStateException()
|
||||
|
||||
// we need to use different model-state to accommodate different albedo for each spectral band but oh well...
|
||||
genTexLoop(model)
|
||||
genTexLoop(model, elevation)
|
||||
// println("$elevation\t${ymaxDisp.text}\t${ymaxDisp2.text}")
|
||||
|
||||
|
||||
/*for (elev in -75..75) {
|
||||
val elevation = Math.toRadians(elev.toDouble())
|
||||
val model = ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevation.abs())
|
||||
genTexLoop(model, elevation)
|
||||
println("$elev\t${ymaxDisp.text}\t${ymaxDisp2.text}")
|
||||
}*/
|
||||
|
||||
|
||||
val tex = Texture(oneScreen)
|
||||
@@ -127,7 +134,7 @@ class Application(val WIDTH: Int, val HEIGHT: Int) : Game() {
|
||||
}
|
||||
|
||||
val outTexWidth = 1
|
||||
val outTexHeight = 256
|
||||
val outTexHeight = 128
|
||||
|
||||
private fun Float.scaleFun() =
|
||||
(1f - 1f / 2f.pow(this/6f)) * 0.97f
|
||||
@@ -142,14 +149,20 @@ class Application(val WIDTH: Int, val HEIGHT: Int) : Game() {
|
||||
)
|
||||
}
|
||||
else {
|
||||
val elevation1 = -Math.toDegrees(elevation)
|
||||
val elevation2 = -Math.toDegrees(elevation) / 28.5
|
||||
val scale = (1f - (1f - 1f / 1.8.pow(elevation1)) * 0.97f).toFloat()
|
||||
val scale2 = (1.0 - (elevation2.pow(E) / E.pow(elevation2))*0.8).toFloat()
|
||||
// maths model: https://www.desmos.com/calculator/cwi7iyzygg
|
||||
|
||||
val x = -Math.toDegrees(elevation).toFloat()
|
||||
// val elevation2 = -Math.toDegrees(elevation) / 28.5
|
||||
val p = 3.5f
|
||||
val q = 7.5f
|
||||
val s = -0.2f
|
||||
val f = (1f - (1f - 1f / 1.8f.pow(x)) * 0.97f).toFloat()
|
||||
// val g = (1.0 - (elevation2.pow(E) / E.pow(elevation2))*0.8).toFloat()
|
||||
val h = ((x / q).pow(p) + 1f).pow(s)
|
||||
CIEXYZ(
|
||||
this.X.scaleFun() * scale * scale2,
|
||||
this.Y.scaleFun() * scale * scale2,
|
||||
this.Z.scaleFun() * scale * scale2,
|
||||
this.X.scaleFun() * f * h,
|
||||
this.Y.scaleFun() * f * h,
|
||||
this.Z.scaleFun() * f * h,
|
||||
this.alpha
|
||||
)
|
||||
}
|
||||
@@ -161,7 +174,7 @@ class Application(val WIDTH: Int, val HEIGHT: Int) : Game() {
|
||||
* Generated texture is as if you took the panorama picture of sky: up 70deg to horizon, east-south-west;
|
||||
* with sun not moving (sun is at exact south, sun's height is adjustable)
|
||||
*/
|
||||
private fun genTexLoop(state: ArHosekSkyModelState) {
|
||||
private fun genTexLoop(state: ArHosekSkyModelState, elevation: Double) {
|
||||
|
||||
fun normaliseY(y: Double): Float {
|
||||
var v = y.coerceAtLeast(0.0)
|
||||
@@ -175,6 +188,7 @@ class Application(val WIDTH: Int, val HEIGHT: Int) : Game() {
|
||||
val ys2 = ArrayList<Float>()
|
||||
|
||||
val halfHeight = oneScreen.height * 0.5
|
||||
val elevationDeg = Math.toDegrees(elevation)
|
||||
|
||||
for (x in 0 until oneScreen.width) {
|
||||
for (y in 0 until oneScreen.height) {
|
||||
@@ -186,17 +200,19 @@ class Application(val WIDTH: Int, val HEIGHT: Int) : Game() {
|
||||
val theta = sqrt(xf*xf + yf*yf) * HALF_PI*/
|
||||
|
||||
// AM-PM mapping (use with WIDTH=1)
|
||||
var yf = (y * 2.0 / oneScreen.height) % 1.0
|
||||
if (elevation < 0) yf *= 1.0 - pow(-elevation / HALF_PI, 0.333)
|
||||
val yp = y % (oneScreen.height / 2)
|
||||
val yi = yp - 3
|
||||
val xf = -elevationDeg / 90.0
|
||||
var yf = (yi / 58.0).coerceIn(0.0, 1.0).mapCircle().coerceInSmoothly(0.0, 0.95)
|
||||
if (elevationDeg < 0) yf *= Skybox.superellipsoidDecay(1.0 / 3.0, xf)
|
||||
val theta = yf * HALF_PI
|
||||
val gamma = if (y < halfHeight) HALF_PI else 3 * HALF_PI
|
||||
val theta = yf.mapCircle() * HALF_PI
|
||||
|
||||
|
||||
|
||||
val xyz = CIEXYZ(
|
||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 0).toFloat(),
|
||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 1).toFloat(),
|
||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 2).toFloat()
|
||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 2).toFloat(),
|
||||
)
|
||||
val xyz2 = xyz.scaleToFit(elevation)
|
||||
ys.add(xyz.Y)
|
||||
@@ -204,12 +220,12 @@ class Application(val WIDTH: Int, val HEIGHT: Int) : Game() {
|
||||
val rgb = xyz2.toRGB().toColor()
|
||||
rgb.a = 1f
|
||||
|
||||
val rgb2 = Color(
|
||||
/*val rgb2 = Color(
|
||||
((rgb.r * 255f).roundToInt() xor 0xAA) / 255f,
|
||||
((rgb.g * 255f).roundToInt() xor 0xAA) / 255f,
|
||||
((rgb.b * 255f).roundToInt() xor 0xAA) / 255f,
|
||||
rgb.a
|
||||
)
|
||||
)*/
|
||||
|
||||
oneScreen.setColor(rgb)
|
||||
oneScreen.drawPixel(x, y)
|
||||
|
||||
@@ -62,9 +62,11 @@ public class App implements ApplicationListener {
|
||||
|
||||
public static final String GAME_NAME = TerrarumAppConfiguration.GAME_NAME;
|
||||
public static final long VERSION_RAW = TerrarumAppConfiguration.VERSION_RAW;
|
||||
public static final String VERSION_TAG = TerrarumAppConfiguration.VERSION_TAG;
|
||||
|
||||
public static final String getVERSION_STRING() {
|
||||
return String.format("%d.%d.%d", VERSION_RAW >>> 48, (VERSION_RAW & 0xffff000000L) >>> 24, VERSION_RAW & 0xffffffL);
|
||||
return String.format("%d.%d.%d", VERSION_RAW >>> 48, (VERSION_RAW & 0xffff000000L) >>> 24, VERSION_RAW & 0xffffffL) +
|
||||
(VERSION_TAG.isBlank() ? "" : "-"+VERSION_TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,12 +269,13 @@ public class App implements ApplicationListener {
|
||||
Gdx.gl20.glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
public static final float UPDATE_RATE = 1f / 64f; // apparent framerate will be limited by update rate
|
||||
public static final int TICK_SPEED = 64;
|
||||
public static final float UPDATE_RATE = 1f / TICK_SPEED; // apparent framerate will be limited by update rate
|
||||
|
||||
private static float loadTimer = 0f;
|
||||
private static final float showupTime = 100f / 1000f;
|
||||
|
||||
private static FloatFrameBuffer renderFBO;
|
||||
private static Float16FrameBuffer renderFBO;
|
||||
|
||||
public static HashSet<File> tempFilePool = new HashSet<>();
|
||||
|
||||
@@ -609,19 +612,21 @@ public class App implements ApplicationListener {
|
||||
|
||||
private static void processScreenshotRequest(FrameBuffer fb) {
|
||||
if (screenshotRequested) {
|
||||
String msg = "Screenshot taken";
|
||||
FrameBufferManager.begin(fb);
|
||||
try {
|
||||
Pixmap p = Pixmap.createFromFrameBuffer(0, 0, fb.getWidth(), fb.getHeight());
|
||||
PixmapIO.writePNG(Gdx.files.absolute(defaultDir+"/Screenshot-"+String.valueOf(System.currentTimeMillis())+".png"), p, 9, true);
|
||||
p.dispose();
|
||||
Terrarum.INSTANCE.getIngame().sendNotification("Screenshot taken");
|
||||
}
|
||||
catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
Terrarum.INSTANCE.getIngame().sendNotification("Failed to take screenshot: "+e.getMessage());
|
||||
msg = ("Failed to take screenshot: "+e.getMessage());
|
||||
}
|
||||
FrameBufferManager.end();
|
||||
screenshotRequested = false;
|
||||
|
||||
Terrarum.INSTANCE.getIngame().sendNotification(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -750,12 +755,12 @@ public class App implements ApplicationListener {
|
||||
(renderFBO.getWidth() != scr.getWidth() ||
|
||||
renderFBO.getHeight() != scr.getHeight())
|
||||
) {
|
||||
renderFBO = new FloatFrameBuffer(
|
||||
renderFBO = new Float16FrameBuffer(
|
||||
scr.getWidth(),
|
||||
scr.getHeight(),
|
||||
false
|
||||
);
|
||||
postProcessorOutFBO2 = new FloatFrameBuffer(
|
||||
postProcessorOutFBO2 = new Float16FrameBuffer(
|
||||
scr.getWidth() * 2,
|
||||
scr.getHeight() * 2,
|
||||
false
|
||||
@@ -1373,6 +1378,8 @@ public class App implements ApplicationListener {
|
||||
* @throws NullPointerException if the specified config simply does not exist.
|
||||
*/
|
||||
public static int getConfigInt(String key) {
|
||||
if (key == null) return -1;
|
||||
|
||||
Object cfg = getConfigMaster(key);
|
||||
|
||||
if (cfg instanceof Integer) return ((int) cfg);
|
||||
|
||||
90
src/net/torvald/terrarum/ControlPresets.kt
Normal file
90
src/net/torvald/terrarum/ControlPresets.kt
Normal file
@@ -0,0 +1,90 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
import com.badlogic.gdx.Input
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-08-24.
|
||||
*/
|
||||
object ControlPresets {
|
||||
|
||||
val wasd = hashMapOf<String, Int>(
|
||||
"control_key_up" to Input.Keys.W,
|
||||
"control_key_left" to Input.Keys.A,
|
||||
"control_key_down" to Input.Keys.S,
|
||||
"control_key_right" to Input.Keys.D,
|
||||
|
||||
"control_key_jump" to Input.Keys.SPACE,
|
||||
"control_key_movementaux" to Input.Keys.SHIFT_LEFT, // movement-auxiliary, or hookshot
|
||||
"control_key_inventory" to Input.Keys.Q,
|
||||
"control_key_interact" to Input.Keys.R,
|
||||
"control_key_discard" to Input.Keys.F,
|
||||
"control_key_close" to Input.Keys.X, // this or hard-coded ESC
|
||||
"control_key_zoom" to Input.Keys.Z,
|
||||
|
||||
"control_key_gamemenu" to Input.Keys.TAB,
|
||||
"control_key_crafting" to Input.Keys.E,
|
||||
"control_key_quicksel" to Input.Keys.CONTROL_LEFT, // pie menu is now LShift because CapsLock is actually used by the my bespoke keyboard input
|
||||
)
|
||||
|
||||
val esdf = hashMapOf<String, Int>(
|
||||
"control_key_up" to Input.Keys.E,
|
||||
"control_key_left" to Input.Keys.S,
|
||||
"control_key_down" to Input.Keys.D,
|
||||
"control_key_right" to Input.Keys.F, // ESDF Masterrace
|
||||
|
||||
"control_key_jump" to Input.Keys.SPACE,
|
||||
"control_key_movementaux" to Input.Keys.A, // movement-auxiliary, or hookshot
|
||||
"control_key_inventory" to Input.Keys.Q,
|
||||
"control_key_interact" to Input.Keys.R,
|
||||
"control_key_discard" to Input.Keys.T,
|
||||
"control_key_close" to Input.Keys.C, // this or hard-coded ESC
|
||||
"control_key_zoom" to Input.Keys.Z,
|
||||
|
||||
"control_key_gamemenu" to Input.Keys.TAB,
|
||||
"control_key_crafting" to Input.Keys.W,
|
||||
"control_key_quicksel" to Input.Keys.SHIFT_LEFT, // pie menu is now LShift because CapsLock is actually used by the my bespoke keyboard input
|
||||
)
|
||||
|
||||
val ijkl = hashMapOf<String, Int>(
|
||||
"control_key_up" to Input.Keys.I,
|
||||
"control_key_left" to Input.Keys.J,
|
||||
"control_key_down" to Input.Keys.K,
|
||||
"control_key_right" to Input.Keys.L,
|
||||
|
||||
"control_key_jump" to Input.Keys.SPACE,
|
||||
"control_key_movementaux" to Input.Keys.SEMICOLON, // movement-auxiliary, or hookshot
|
||||
"control_key_inventory" to Input.Keys.P,
|
||||
"control_key_interact" to Input.Keys.U,
|
||||
"control_key_discard" to Input.Keys.Y,
|
||||
"control_key_close" to Input.Keys.M, // this or hard-coded ESC
|
||||
"control_key_zoom" to Input.Keys.SLASH,
|
||||
|
||||
"control_key_gamemenu" to Input.Keys.LEFT_BRACKET,
|
||||
"control_key_crafting" to Input.Keys.O,
|
||||
"control_key_quicksel" to Input.Keys.APOSTROPHE, // pie menu is now LShift because CapsLock is actually used by the my bespoke keyboard input
|
||||
)
|
||||
|
||||
val empty = hashMapOf<String, Int>()
|
||||
|
||||
val presets = hashMapOf( // unordered
|
||||
"WASD" to wasd,
|
||||
"ESDF" to esdf,
|
||||
"IJKL" to ijkl,
|
||||
"Custom" to empty,
|
||||
)
|
||||
|
||||
val presetLabels = listOf( // ordered
|
||||
"WASD",
|
||||
"ESDF",
|
||||
"IJKL",
|
||||
"Custom",
|
||||
)
|
||||
|
||||
fun getKey(label: String?): Int {
|
||||
if (label == null) return -1
|
||||
|
||||
val presetName = App.getConfigString("control_preset_keyboard") ?: "Custom"
|
||||
|
||||
return (presets[presetName] ?: throw IllegalStateException("No such keyboard preset: $presetName")).getOrDefault(label, App.getConfigInt(label))
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,8 @@ object DefaultConfig {
|
||||
|
||||
"usexinput" to true, // when FALSE, LT+RT input on xbox controller is impossible
|
||||
|
||||
"control_preset_keyboard" to "WASD",
|
||||
|
||||
"control_gamepad_keyn" to 3,
|
||||
"control_gamepad_keyw" to 2,
|
||||
"control_gamepad_keys" to 0,
|
||||
|
||||
@@ -531,6 +531,9 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
fun onConfigChange() {
|
||||
}
|
||||
}
|
||||
|
||||
inline fun Lock.lock(body: () -> Unit) {
|
||||
|
||||
@@ -62,9 +62,12 @@ basegame
|
||||
* e.g. 0x02010034 will be translated as 2.1.52
|
||||
*
|
||||
*/
|
||||
const val VERSION_RAW: Long = 0x0000_000003_000002
|
||||
const val VERSION_RAW: Long = 0x0000_000003_000003
|
||||
// Commit counts up to the Release 0.3.0: 2259
|
||||
// Commit counts up to the Release 0.3.1: 2278
|
||||
// Commit counts up to the Release 0.3.2: 2732
|
||||
|
||||
const val VERSION_TAG: String = "test002"
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// CONFIGURATION FOR TILE MAKER //
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.badlogic.gdx.math.Matrix4
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.App.IS_DEVELOPMENT_BUILD
|
||||
import net.torvald.terrarum.gamecontroller.KeyToggler
|
||||
import net.torvald.terrarum.ui.BasicDebugInfoWindow
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
@@ -150,9 +151,10 @@ object TerrarumPostProcessor : Disposable {
|
||||
}
|
||||
|
||||
// draw dev build notifiers
|
||||
if (App.IS_DEVELOPMENT_BUILD && Terrarum.ingame != null) {
|
||||
// omitting this screws up HQ2X render for some reason
|
||||
if (Terrarum.ingame != null) {
|
||||
batch.inUse {
|
||||
batch.color = safeAreaCol
|
||||
batch.color = if (IS_DEVELOPMENT_BUILD) safeAreaCol else colourNull
|
||||
App.fontGame.draw(it, thisIsDebugStr, 5f, App.scr.height - 24f)
|
||||
}
|
||||
}
|
||||
@@ -192,6 +194,7 @@ object TerrarumPostProcessor : Disposable {
|
||||
return outFBO
|
||||
}
|
||||
private val rng = HQRNG()
|
||||
private val colourNull = Color(0)
|
||||
|
||||
private fun Double.format(digits: Int) = "%.${digits}f".format(this)
|
||||
private fun Float.format(digits: Int) = "%.${digits}f".format(this)
|
||||
|
||||
@@ -209,8 +209,8 @@ class BlockCodex {
|
||||
prop.isSolid = record.boolVal("solid")
|
||||
//prop.isClear = record.boolVal("clear")
|
||||
|
||||
prop.isPlatform = prop.tags.contains("PLATFORM")
|
||||
prop.isActorBlock = prop.tags.contains("ACTORBLOCK")
|
||||
prop.isPlatform = prop.hasTag("PLATFORM")
|
||||
prop.isActorBlock = prop.hasTag("ACTORBLOCK")
|
||||
|
||||
prop.isWallable = record.boolVal("wall")
|
||||
prop.maxSupport = record.intVal("grav")
|
||||
|
||||
@@ -75,6 +75,8 @@ class BlockProp {
|
||||
BlockCodex[BlockCodex.tileToVirtual[id]!![offset]]._lumCol.lane(channel)
|
||||
}
|
||||
|
||||
fun hasTag(s: String) = tags.contains(s)
|
||||
|
||||
/**
|
||||
* @param luminosity
|
||||
*/
|
||||
|
||||
@@ -19,7 +19,7 @@ fun main() {
|
||||
// y: increasing turbidity (1.0 .. 10.0, in steps of 0.333)
|
||||
// x: elevations (-75 .. 75 in steps of 1, then albedo of [0.1, 0.3, 0.5, 0.7, 0.9])
|
||||
val texh = Skybox.gradSize * Skybox.turbCnt
|
||||
val texw = Skybox.elevCnt * Skybox.albedoCnt
|
||||
val texw = Skybox.elevCnt * Skybox.albedoCnt * 2
|
||||
val TGA_HEADER_SIZE = 18
|
||||
|
||||
val bytes = ByteArray(TGA_HEADER_SIZE + texw * texh * 4 + 26)
|
||||
@@ -44,47 +44,50 @@ fun main() {
|
||||
println("Generating texture atlas ($texw x $texh)...")
|
||||
|
||||
// write pixels
|
||||
for (albedo0 in 0 until Skybox.albedoCnt) {
|
||||
val albedo = Skybox.albedos[albedo0]
|
||||
println("Albedo=$albedo")
|
||||
for (turb0 in 0 until Skybox.turbCnt) {
|
||||
val turbidity = Skybox.turbiditiesD[turb0]
|
||||
println("....... Turbidity=$turbidity")
|
||||
for (elev0 in 0 until Skybox.elevCnt) {
|
||||
val elevationDeg = Skybox.elevationsD[elev0]
|
||||
val elevationRad = Math.toRadians(elevationDeg)
|
||||
for (gammaPair in 0..1) {
|
||||
for (albedo0 in 0 until Skybox.albedoCnt) {
|
||||
val albedo = Skybox.albedos[albedo0]
|
||||
println("Albedo=$albedo")
|
||||
for (turb0 in 0 until Skybox.turbCnt) {
|
||||
val turbidity = Skybox.turbiditiesD[turb0]
|
||||
println("....... Turbidity=$turbidity")
|
||||
for (elev0 in 0 until Skybox.elevCnt) {
|
||||
val elevationDeg = Skybox.elevationsD[elev0]
|
||||
val elevationRad = Math.toRadians(elevationDeg)
|
||||
// println("... Elevation: $elevationDeg")
|
||||
|
||||
val state = ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevationRad.abs())
|
||||
val state =
|
||||
ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevationRad.abs())
|
||||
|
||||
for (yp in 0 until Skybox.gradSize) {
|
||||
val yi = yp - 3
|
||||
val xf = -elevationDeg / 90.0
|
||||
var yf = (yi / 58.0).coerceIn(0.0, 1.0).mapCircle().coerceInSmoothly(0.0, 0.95)
|
||||
for (yp in 0 until Skybox.gradSize) {
|
||||
val yi = yp - 10
|
||||
val xf = -elevationDeg / 90.0
|
||||
var yf = (yi / 58.0).coerceIn(0.0, 1.0).mapCircle().coerceInSmoothly(0.0, 0.95)
|
||||
|
||||
// experiments visualisation: https://www.desmos.com/calculator/5crifaekwa
|
||||
// experiments visualisation: https://www.desmos.com/calculator/5crifaekwa
|
||||
// if (elevationDeg < 0) yf *= 1.0 - pow(xf, 0.333)
|
||||
// if (elevationDeg < 0) yf *= -2.0 * asin(xf - 1.0) / PI
|
||||
if (elevationDeg < 0) yf *= Skybox.superellipsoidDecay(1.0 / 3.0, xf)
|
||||
val theta = yf * HALF_PI
|
||||
// vertical angle, where 0 is zenith, ±90 is ground (which is odd)
|
||||
if (elevationDeg < 0) yf *= Skybox.superellipsoidDecay(1.0 / 3.0, xf)
|
||||
val theta = yf * HALF_PI
|
||||
// vertical angle, where 0 is zenith, ±90 is ground (which is odd)
|
||||
|
||||
// println("$yp\t$theta")
|
||||
|
||||
val xyz = CIEXYZ(
|
||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, HALF_PI, 0).toFloat(),
|
||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, HALF_PI, 1).toFloat(),
|
||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, HALF_PI, 2).toFloat()
|
||||
)
|
||||
val xyz2 = xyz.scaleToFit(elevationDeg)
|
||||
val rgb = xyz2.toRGB().toColor()
|
||||
val colour = rgb.toIntBits().toLittle()
|
||||
val xyz = CIEXYZ(
|
||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, (gammaPair * 2f + 1f) * HALF_PI, 0).toFloat(),
|
||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, (gammaPair * 2f + 1f) * HALF_PI, 1).toFloat(),
|
||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, (gammaPair * 2f + 1f) * HALF_PI, 2).toFloat()
|
||||
)
|
||||
val xyz2 = xyz.scaleToFit(elevationDeg)
|
||||
val rgb = xyz2.toRGB().toColor()
|
||||
val colour = rgb.toIntBits().toLittle()
|
||||
|
||||
val imgOffX = (albedo0 * Skybox.elevCnt + elev0)
|
||||
val imgOffY = texh - 1 - (Skybox.gradSize * turb0 + yp)
|
||||
val fileOffset = TGA_HEADER_SIZE + 4 * (imgOffY * texw + imgOffX)
|
||||
for (i in 0..3) {
|
||||
bytes[fileOffset + i] = colour[bytesLut[i]]
|
||||
val imgOffX = albedo0 * Skybox.elevCnt + elev0 + Skybox.elevCnt * Skybox.albedoCnt * gammaPair
|
||||
val imgOffY = texh - 1 - (Skybox.gradSize * turb0 + yp)
|
||||
val fileOffset = TGA_HEADER_SIZE + 4 * (imgOffY * texw + imgOffX)
|
||||
for (i in 0..3) {
|
||||
bytes[fileOffset + i] = colour[bytesLut[i]]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,7 +96,7 @@ fun main() {
|
||||
|
||||
println("Atlas generation done!")
|
||||
|
||||
File("./assets/mods/basegame/weathers/main_skybox.tga").writeBytes(bytes)
|
||||
File("./assets/clut/skybox.tga").writeBytes(bytes)
|
||||
}
|
||||
|
||||
private val bytesLut = arrayOf(2,1,0,3,2,1,0,3) // For some reason BGRA order is what makes it work
|
||||
@@ -13,6 +13,8 @@ import net.torvald.parametricsky.ArHosekSkyModel
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.abs
|
||||
import net.torvald.terrarum.floorToInt
|
||||
import net.torvald.terrarum.toInt
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import kotlin.math.*
|
||||
|
||||
@@ -25,7 +27,7 @@ object Skybox : Disposable {
|
||||
private const val PI = 3.141592653589793
|
||||
private const val TWO_PI = 6.283185307179586
|
||||
|
||||
const val gradSize = 64
|
||||
const val gradSize = 78
|
||||
|
||||
private lateinit var gradTexBinLowAlbedo: Array<TextureRegion>
|
||||
private lateinit var gradTexBinHighAlbedo: Array<TextureRegion>
|
||||
@@ -37,6 +39,7 @@ object Skybox : Disposable {
|
||||
fun loadlut() {
|
||||
tex = Texture(Gdx.files.internal("assets/clut/skybox.png"))
|
||||
tex.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
|
||||
tex.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat)
|
||||
texRegions = TextureRegionPack(tex, 2, gradSize - 2, 0, 2, 0, 1)
|
||||
texStripRegions = TextureRegionPack(tex, elevCnt, gradSize - 2, 0, 2, 0, 1)
|
||||
}
|
||||
@@ -50,28 +53,67 @@ object Skybox : Disposable {
|
||||
}*/
|
||||
|
||||
// use external LUT
|
||||
operator fun get(elevationDeg: Double, turbidity: Double, albedo: Double): TextureRegion {
|
||||
val elev = elevationDeg.coerceIn(-elevMax, elevMax).roundToInt().plus(elevMax).roundToInt()
|
||||
val turb = turbidity.coerceIn(1.0, 10.0).minus(1.0).times(turbDivisor).roundToInt()
|
||||
val alb = albedo.coerceIn(0.1, 0.9).minus(0.1).times(turbDivisor).roundToInt()
|
||||
//printdbg(this, "elev $elevationDeg->$elev; turb $turbidity->$turb; alb $albedo->$alb")
|
||||
return texRegions.get(alb * elevCnt + elev, turb)
|
||||
operator fun get(elevationDeg: Double, turbidity: Double, albedo: Double, isAfternoon: Boolean): TextureRegion {
|
||||
TODO()
|
||||
}
|
||||
|
||||
fun getUV(elevationDeg: Double, turbidity: Double, albedo: Double): Pair<Texture, FloatArray> {
|
||||
val turb = turbidity.coerceIn(1.0, 10.0).minus(1.0).times(turbDivisor).roundToInt()
|
||||
val alb = albedo.coerceIn(0.1, 0.9).minus(0.1).times(turbDivisor).roundToInt()
|
||||
val region = texStripRegions.get(alb, turb)
|
||||
data class SkyboxRenderInfo(
|
||||
val texture: Texture,
|
||||
val uvs: FloatArray,
|
||||
val turbidityPoint: Float,
|
||||
val albedoPoint: Float,
|
||||
)
|
||||
|
||||
val elev = elevationDeg.coerceIn(-elevMax, elevMax).plus(elevMax).div(elevations.last.toDouble()).div(albedoCnt).times((elevCnt - 1.0) / elevCnt)
|
||||
fun getUV(elevationDeg: Double, turbidity: Double, albedo: Double): SkyboxRenderInfo {
|
||||
val turb = turbidity.coerceIn(turbiditiesD.first(), turbiditiesD.last()).minus(1.0).times(turbDivisor)
|
||||
val turbLo = turb.floorToInt()
|
||||
val turbHi = min(turbCnt - 1, turbLo + 1)
|
||||
val alb = albedo.coerceIn(albedos.first(), albedos.last()).times(5.0)
|
||||
val albLo = alb.floorToInt()
|
||||
val albHi = min(albedoCnt - 1, albLo + 1)
|
||||
val elev = elevationDeg.coerceIn(-elevMax, elevMax).plus(elevMax).div(elevations.last.toDouble()).div(albedoCnt * 2).times((elevCnt - 1.0) / elevCnt)
|
||||
|
||||
val u = region.u + (0.5f / tex.width) + elev.toFloat() // because of the nature of bilinear interpolation, half pixels from the edges must be discarded
|
||||
// A: morn, turbLow, albLow
|
||||
// B: noon, turbLow, albLow
|
||||
// C: morn, turbHigh, albLow
|
||||
// D: noon, turbHigh, albLow
|
||||
// E: morn, turbLow, albHigh
|
||||
// F: noon, turbLow, albHigh
|
||||
// G: morn, turbHigh, albHigh
|
||||
// H: noon, turbHigh, albHigh
|
||||
|
||||
return tex to floatArrayOf(
|
||||
u,
|
||||
region.v,
|
||||
u,
|
||||
region.v2
|
||||
val regionA = texStripRegions.get(albLo + albedoCnt * 0, turbLo)
|
||||
val regionB = texStripRegions.get(albLo + albedoCnt * 1, turbLo)
|
||||
val regionC = texStripRegions.get(albLo + albedoCnt * 0, turbHi)
|
||||
val regionD = texStripRegions.get(albLo + albedoCnt * 1, turbHi)
|
||||
val regionE = texStripRegions.get(albHi + albedoCnt * 0, turbLo)
|
||||
val regionF = texStripRegions.get(albHi + albedoCnt * 1, turbLo)
|
||||
val regionG = texStripRegions.get(albHi + albedoCnt * 0, turbHi)
|
||||
val regionH = texStripRegions.get(albHi + albedoCnt * 1, turbHi)
|
||||
// (0.5f / tex.width): because of the nature of bilinear interpolation, half pixels from the edges must be discarded
|
||||
val uA = regionA.u + (0.5f / tex.width) + elev.toFloat()
|
||||
val uB = regionB.u + (0.5f / tex.width) + elev.toFloat()
|
||||
val uC = regionC.u + (0.5f / tex.width) + elev.toFloat()
|
||||
val uD = regionD.u + (0.5f / tex.width) + elev.toFloat()
|
||||
val uE = regionE.u + (0.5f / tex.width) + elev.toFloat()
|
||||
val uF = regionF.u + (0.5f / tex.width) + elev.toFloat()
|
||||
val uG = regionG.u + (0.5f / tex.width) + elev.toFloat()
|
||||
val uH = regionH.u + (0.5f / tex.width) + elev.toFloat()
|
||||
|
||||
return SkyboxRenderInfo(
|
||||
tex,
|
||||
floatArrayOf(
|
||||
uA, regionA.v, uA, regionA.v2,
|
||||
uB, regionB.v, uB, regionB.v2,
|
||||
uC, regionC.v, uC, regionC.v2,
|
||||
uD, regionD.v, uD, regionD.v2,
|
||||
uE, regionE.v, uE, regionE.v2,
|
||||
uF, regionF.v, uF, regionF.v2,
|
||||
uG, regionG.v, uG, regionG.v2,
|
||||
uH, regionH.v, uH, regionH.v2,
|
||||
),
|
||||
(turb - turbLo).toFloat(),
|
||||
(alb - albLo).toFloat(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -88,15 +130,20 @@ object Skybox : Disposable {
|
||||
)
|
||||
}
|
||||
else {
|
||||
val deg1 = (-elevationDeg / elevMax).pow(0.93).times(-elevMax)
|
||||
val elevation1 = -deg1
|
||||
val elevation2 = -deg1 / 28.5
|
||||
val scale = (1f - (1f - 1f / 1.8.pow(elevation1)) * 0.97f).toFloat()
|
||||
val scale2 = (1.0 - (elevation2.pow(E) / E.pow(elevation2))*0.8).toFloat()
|
||||
// maths model: https://www.desmos.com/calculator/cwi7iyzygg
|
||||
|
||||
val x = -elevationDeg.toFloat()
|
||||
// val elevation2 = elevationDeg.toFloat() / 28.5f
|
||||
val p = 3.5f
|
||||
val q = 7.5f
|
||||
val s = -0.2f
|
||||
val f = (1f - (1f - 1f / 1.8f.pow(x)) * 0.97f).toFloat()
|
||||
// val g = (1.0 - (elevation2.pow(E) / E.pow(elevation2))*0.8).toFloat()
|
||||
val h = ((x / q).pow(p) + 1f).pow(s)
|
||||
CIEXYZ(
|
||||
this.X.scaleFun() * scale * scale2,
|
||||
this.Y.scaleFun() * scale * scale2,
|
||||
this.Z.scaleFun() * scale * scale2,
|
||||
this.X.scaleFun() * f * h,
|
||||
this.Y.scaleFun() * f * h,
|
||||
this.Z.scaleFun() * f * h,
|
||||
this.alpha
|
||||
)
|
||||
}
|
||||
@@ -105,15 +152,13 @@ object Skybox : Disposable {
|
||||
val elevations = (0..150)
|
||||
val elevMax = elevations.last / 2.0
|
||||
val elevationsD = elevations.map { -elevMax + it } // -75, -74, -73, ..., 74, 75 // (specifically using whole number of angles because angle units any finer than 1.0 would make "hack" sunsut happen too fast)
|
||||
val turbidities = (0..45) // 1, 1.2, 1.4, 1.6, ..., 10.0
|
||||
val turbidities = (0..25) // 1, 1.2, 1.4, 1.6, ..., 6.0
|
||||
val turbDivisor = 5.0
|
||||
val turbiditiesD = turbidities.map { 1.0 + it / turbDivisor }
|
||||
val albedos = arrayOf(0.1, 0.3, 0.5, 0.7, 0.9)
|
||||
val albedos = arrayOf(0.0, 0.2, 0.4, 0.6, 0.8, 1.0)
|
||||
val elevCnt = elevations.count()
|
||||
val turbCnt = turbidities.count()
|
||||
val albedoCnt = albedos.size
|
||||
val albedoLow = 0.1
|
||||
val albedoHight = 0.8 // for theoretical "winter wonderland"?
|
||||
val gamma = HALF_PI
|
||||
|
||||
internal fun Double.mapCircle() = sin(HALF_PI * this)
|
||||
@@ -121,8 +166,7 @@ object Skybox : Disposable {
|
||||
internal fun initiate() {
|
||||
printdbg(this, "Initialising skybox model")
|
||||
|
||||
gradTexBinLowAlbedo = getTexturmaps(albedoLow)
|
||||
gradTexBinHighAlbedo = getTexturmaps(albedoHight)
|
||||
TODO()
|
||||
|
||||
App.disposables.add(this)
|
||||
|
||||
@@ -170,6 +214,11 @@ object Skybox : Disposable {
|
||||
|
||||
/**
|
||||
* To get the idea what the fuck is going on here, please refer to https://www.desmos.com/calculator/snqglcu2wl
|
||||
*
|
||||
* Sidenote: the original model involved two cosine curves, but since its Taylor series begins with x^2, I figured
|
||||
* quadratic curve ought to be good enough, and the error against the original model was below 1/255 for
|
||||
* reasonable range of p, and that's the reason I stopped at x^2 rather than also taking x^4 into the approximated
|
||||
* model that is the code below.
|
||||
*/
|
||||
internal fun smoothLinear(p: Double, x0: Double): Double {
|
||||
val x = x0 - 0.5
|
||||
@@ -198,7 +247,7 @@ object Skybox : Disposable {
|
||||
// printdbg(this, "elev $elevationDeg turb $turbidity")
|
||||
|
||||
for (yp in 0 until gradSize) {
|
||||
val yi = yp - 3
|
||||
val yi = yp - 10
|
||||
val xf = -elevationDeg / 90.0
|
||||
var yf = (yi / 58.0).coerceIn(0.0, 1.0).mapCircle().coerceInSmoothly(0.0, 0.95)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ internal object Authenticator : ConsoleCommand {
|
||||
println("auth passwd: '$pwd'")
|
||||
println("hash: $hashedPwd")
|
||||
|
||||
if ("09ccf5067db6f58265b004829e33e715e819ba0984f1e1fcef49c36fcd5f745f".equals(hashedPwd, ignoreCase = true)) {
|
||||
if ("2d962f949f55906ac47f16095ded190c9e44d95920259b8f36c2e54bd75df173".equals(hashedPwd, ignoreCase = true)) {
|
||||
// beedle
|
||||
val msg = if (a) "Locked" else "Authenticated"
|
||||
Echo(msg)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -145,6 +145,9 @@ class Hitbox {
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize the hitbox centred around the "canonical" point.
|
||||
*/
|
||||
fun canonicalResize(w: Double, h: Double): Hitbox {
|
||||
// sx_1 + 0.5w_1 = sx_2 + 0.5w_2 // equals because the final point must not move. sx_1: old start-x, sx_2: new start-x which is what we want
|
||||
// sx_2 = sx_1 + 0.5w_1 - 0.5w_2 // move variables to right-hand side to derive final value sx_2
|
||||
|
||||
@@ -5,14 +5,11 @@ import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.InputAdapter
|
||||
import com.badlogic.gdx.controllers.Controllers
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.App.printdbgerr
|
||||
import net.torvald.terrarum.ItemCodex
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.controller.TerrarumController
|
||||
import net.torvald.terrarum.floorToInt
|
||||
import net.torvald.terrarum.gameactors.AVKey
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
import net.torvald.terrarum.gameworld.fmod
|
||||
@@ -168,7 +165,7 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
|
||||
|
||||
// pie menu
|
||||
if (App.getConfigIntArray("control_key_quickselalt").contains(keycode)
|
||||
|| keycode == App.getConfigInt("control_key_quicksel")) {
|
||||
|| keycode == ControlPresets.getKey("control_key_quicksel")) {
|
||||
terrarumIngame.uiPieMenu.setAsOpen()
|
||||
terrarumIngame.uiQuickBar.setAsClose()
|
||||
}
|
||||
@@ -194,7 +191,7 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
|
||||
|
||||
private fun tKeyUp(keycode: Int): Boolean {
|
||||
if (App.getConfigIntArray("control_key_quickselalt").contains(keycode)
|
||||
|| keycode == App.getConfigInt("control_key_quicksel")) {
|
||||
|| keycode == ControlPresets.getKey("control_key_quicksel")) {
|
||||
terrarumIngame.uiPieMenu.setAsClose()
|
||||
terrarumIngame.uiQuickBar.setAsOpen()
|
||||
}
|
||||
|
||||
@@ -359,6 +359,8 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
|
||||
return this
|
||||
}
|
||||
|
||||
fun hasTag(s: String) = tags.contains(s)
|
||||
|
||||
|
||||
companion object {
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package net.torvald.terrarum.gameworld
|
||||
|
||||
import net.torvald.terrarum.modulebasegame.worldgenerator.TWO_PI
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
|
||||
/**
|
||||
@@ -57,8 +56,10 @@ import kotlin.math.sin
|
||||
*/
|
||||
class WorldTime(initTime: Long = 0L) {
|
||||
|
||||
@Transient private val TWO_PI = Math.PI * 2.0
|
||||
|
||||
/** It is not recommended to directly modify the TIME_T. Use provided methods instead. */
|
||||
var TIME_T = 0L // Epoch: Year 125 Spring 1st, 0h00:00 (Mondag) // 125-01-01
|
||||
var TIME_T = 0L // Epoch: Year 1 Spring 1st, 0h00:00 (Mondag) // 0001-01-01
|
||||
|
||||
init {
|
||||
TIME_T = initTime
|
||||
@@ -151,21 +152,7 @@ class WorldTime(initTime: Long = 0L) {
|
||||
@Transient private val REAL_SEC_TO_GAME_SECS = 1.0 / GAME_MIN_TO_REAL_SEC // how slow is real-life clock (second-wise) relative to the ingame one
|
||||
|
||||
// NOTE: ingame calendars (the fixture with GUI) should use symbols AND fullnames; the watch already uses shot daynames
|
||||
val DAY_NAMES = arrayOf(//daynames are taken from Nynorsk (å -> o)
|
||||
"Mondag", "Tysdag", "Midtveke" //middle-week
|
||||
, "Torsdag", "Fredag", "Laurdag", "Sundag", "Verddag" //From Norsk word 'verd'
|
||||
)
|
||||
val DAY_NAMES_SHORT = arrayOf("Mon", "Tys", "Mid", "Tor", "Fre", "Lau", "Sun", "Ver")
|
||||
|
||||
// dwarven calendar of 12 monthes
|
||||
/*val MONTH_NAMES = arrayOf(
|
||||
"Opal", "Obsidian", "Granite", "Slate", "Felsite", "Hematite",
|
||||
"Malachite", "Galena", "Limestone", "Sandstone", "Timber", "Moonstone"
|
||||
)
|
||||
val MONTH_NAMES_SHORT = arrayOf("Opal", "Obsi", "Gran", "Slat", "Fels", "Hema",
|
||||
"Mala", "Gale", "Lime", "Sand", "Timb", "Moon")*/
|
||||
val MONTH_NAMES = arrayOf("Spring", "Summer", "Autumn", "Winter")
|
||||
val MONTH_NAMES_SHORT = arrayOf("Spri", "Summ", "Autm", "Wint")
|
||||
|
||||
companion object {
|
||||
/** Each day is displayed as 24 hours, but in real-life clock it's 22 mins long */
|
||||
@@ -181,7 +168,7 @@ class WorldTime(initTime: Long = 0L) {
|
||||
|
||||
const val MONTH_LENGTH = 30 // ingame calendar specific
|
||||
|
||||
const val EPOCH_YEAR = 125
|
||||
const val EPOCH_YEAR = 1
|
||||
|
||||
val YEAR_SECONDS = DAY_LENGTH * YEAR_DAYS
|
||||
|
||||
@@ -203,6 +190,31 @@ class WorldTime(initTime: Long = 0L) {
|
||||
|
||||
val LUNAR_CYCLE: Int = 29 * DAY_LENGTH + 12 * HOUR_SEC + 44 * MINUTE_SEC + 3 // 29 days, 12 hours, 44 minutes, and 3 seconds in-game calendar
|
||||
const val DIURNAL_MOTION_LENGTH = 86636f
|
||||
|
||||
val DAY_NAMES = arrayOf(//daynames are taken from Nynorsk (å -> o)
|
||||
"MONDAG", "TYSDAG", "MIDTVEKE" //middle-week
|
||||
, "TORSDAG", "FREDAG", "LAURDAG", "SUNDAG", "VERDDAG" //From Norsk word 'verd'
|
||||
)
|
||||
val DAY_NAMES_SHORT = arrayOf("MON", "TYS", "MID", "TOR", "FRE", "LAU", "SUN", "VER")
|
||||
// dwarven calendar of 12 monthes
|
||||
/*val MONTH_NAMES = arrayOf(
|
||||
"Opal", "Obsidian", "Granite", "Slate", "Felsite", "Hematite",
|
||||
"Malachite", "Galena", "Limestone", "Sandstone", "Timber", "Moonstone"
|
||||
)
|
||||
val MONTH_NAMES_SHORT = arrayOf("Opal", "Obsi", "Gran", "Slat", "Fels", "Hema",
|
||||
"Mala", "Gale", "Lime", "Sand", "Timb", "Moon")*/
|
||||
val MONTH_NAMES = arrayOf("SPRING", "SUMMER", "AUTUMN", "WINTER")
|
||||
val MONTH_NAMES_SHORT = arrayOf("SPRI", "SUMM", "AUTM", "WINT")
|
||||
|
||||
val DAY_NAMES_LANG_KEYS = DAY_NAMES.map { "CONTEXT_CALENDAR_DAY_${it}_DNT" }
|
||||
val DAY_NAMES_SHORT_LANG_KEYS = DAY_NAMES_SHORT.map { "CONTEXT_CALENDAR_DAY_${it}_DNT" }
|
||||
val MONTH_NAMES_LANG_KEYS = MONTH_NAMES.map { "CONTEXT_CALENDAR_SEASON_${it}" }
|
||||
val MONTH_NAMES_SHORT_LANG_KEYS = MONTH_NAMES_SHORT.map { "CONTEXT_CALENDAR_SEASON_${it}" }
|
||||
|
||||
fun getDayName(index: Int) = Lang[DAY_NAMES_LANG_KEYS[index]]
|
||||
fun getDayNameShort(index: Int) = Lang[DAY_NAMES_SHORT_LANG_KEYS[index]]
|
||||
fun getMonthName(index: Int) = Lang[MONTH_NAMES_LANG_KEYS[index - 1]]
|
||||
fun getMonthNameShort(index: Int) = Lang[MONTH_NAMES_SHORT_LANG_KEYS[index - 1]]
|
||||
}
|
||||
|
||||
fun update(delta: Float) {
|
||||
@@ -228,27 +240,30 @@ class WorldTime(initTime: Long = 0L) {
|
||||
TIME_T += t
|
||||
}
|
||||
|
||||
val dayName: String
|
||||
get() = DAY_NAMES[dayOfWeek]
|
||||
|
||||
fun Long.toPositiveInt() = this.and(0x7FFFFFFF).toInt()
|
||||
fun Long.abs() = Math.abs(this)
|
||||
|
||||
/** Format: "%A, %Y %B %d %X" */
|
||||
fun getFormattedTime() = "${getDayNameShort()}, " +
|
||||
"$years " +
|
||||
"${getMonthNameFull()} " +
|
||||
"$calendarDay " +
|
||||
"${String.format("%02d", hours)}:" +
|
||||
"${String.format("%02d", minutes)}:" +
|
||||
"${String.format("%02d", seconds)}"
|
||||
/** Format: "ɣ%Y %B %d %A, %X" */
|
||||
fun getFormattedTime() =
|
||||
"ɣ$years " +
|
||||
"${getMonthNameFull()} " +
|
||||
"$calendarDay " +
|
||||
"${getDayNameFull()}, " +
|
||||
"${String.format("%02d", hours)}:" +
|
||||
"${String.format("%02d", minutes)}:" +
|
||||
"${String.format("%02d", seconds)}"
|
||||
fun getFormattedCalendarDay() =
|
||||
"ɣ$years " +
|
||||
"${getMonthNameFull()} " +
|
||||
"$calendarDay " +
|
||||
"${getDayNameFull()}"
|
||||
fun getShortTime() = "${years.toString().padStart(4, '0')}-${getMonthNameShort()}-${calendarDay.toString().padStart(2, '0')}"
|
||||
fun getFilenameTime() = "${years.toString().padStart(4, '0')}${calendarMonth.toString().padStart(2, '0')}${calendarDay.toString().padStart(2, '0')}"
|
||||
|
||||
fun getDayNameFull() = DAY_NAMES[dayOfWeek]
|
||||
fun getDayNameShort() = DAY_NAMES_SHORT[dayOfWeek]
|
||||
fun getMonthNameFull() = MONTH_NAMES[calendarMonth - 1]
|
||||
fun getMonthNameShort() = MONTH_NAMES_SHORT[calendarMonth - 1]
|
||||
fun getDayNameFull() = getDayName(dayOfWeek)
|
||||
fun getDayNameShort() = getDayNameShort(dayOfWeek)
|
||||
fun getMonthNameFull() = getMonthName(calendarMonth)
|
||||
fun getMonthNameShort() = getMonthNameShort(calendarMonth)
|
||||
|
||||
override fun toString() = getFormattedTime()
|
||||
}
|
||||
@@ -152,6 +152,15 @@ object Lang {
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
fun getAndUseTemplate(key: String, capitalise: Boolean = true, vararg arguments: Any?): String {
|
||||
var raw = get(key, capitalise)
|
||||
arguments.forEachIndexed { index, it0 ->
|
||||
val it = if (capitalise) it0.toString().capitalize() else it0.toString()
|
||||
raw = raw.replace("{${index}}", it)
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
||||
/**
|
||||
* Does NOT parse the operators
|
||||
*/
|
||||
|
||||
@@ -302,6 +302,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
|
||||
IngameRenderer.setRenderedWorld(gameWorld)
|
||||
WeatherMixer.internalReset()
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
|
||||
@@ -4,11 +4,10 @@ import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import com.badlogic.gdx.graphics.glutils.FloatFrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.Float16FrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.App.*
|
||||
@@ -53,20 +52,20 @@ object IngameRenderer : Disposable {
|
||||
private lateinit var blurWriteQuad2: Mesh
|
||||
// private lateinit var blurWriteQuad4: Mesh
|
||||
|
||||
private lateinit var lightmapFbo: FloatFrameBuffer
|
||||
private lateinit var fboRGB: FloatFrameBuffer
|
||||
private lateinit var fboRGB_lightMixed: FloatFrameBuffer
|
||||
private lateinit var fboA: FloatFrameBuffer
|
||||
private lateinit var fboA_lightMixed: FloatFrameBuffer
|
||||
private lateinit var fboMixedOut: FloatFrameBuffer
|
||||
private lateinit var lightmapFbo: Float16FrameBuffer
|
||||
private lateinit var fboRGB: Float16FrameBuffer
|
||||
private lateinit var fboRGB_lightMixed: Float16FrameBuffer
|
||||
private lateinit var fboA: Float16FrameBuffer
|
||||
private lateinit var fboA_lightMixed: Float16FrameBuffer
|
||||
private lateinit var fboMixedOut: Float16FrameBuffer
|
||||
private lateinit var rgbTex: TextureRegion
|
||||
private lateinit var aTex: TextureRegion
|
||||
private lateinit var mixedOutTex: TextureRegion
|
||||
private lateinit var lightTex: TextureRegion
|
||||
private lateinit var blurTex: TextureRegion
|
||||
|
||||
private lateinit var fboBlurHalf: FloatFrameBuffer
|
||||
// private lateinit var fboBlurQuarter: FloatFrameBuffer
|
||||
private lateinit var fboBlurHalf: Float16FrameBuffer
|
||||
// private lateinit var fboBlurQuarter: Float16FrameBuffer
|
||||
|
||||
// you must have lightMixed FBO; otherwise you'll be reading from unbaked FBO and it freaks out GPU
|
||||
|
||||
@@ -256,7 +255,9 @@ object IngameRenderer : Disposable {
|
||||
gdxClearAndEnableBlend(0f, 0f, 0f, 0f)
|
||||
|
||||
// draw sky
|
||||
WeatherMixer.render(camera, batch, world)
|
||||
measureDebugTime("WeatherMixer.render") {
|
||||
WeatherMixer.render(camera, batch, world)
|
||||
}
|
||||
|
||||
|
||||
// normal behaviour
|
||||
@@ -694,7 +695,7 @@ object IngameRenderer : Disposable {
|
||||
|
||||
private const val KAWASE_POWER = 1.5f
|
||||
|
||||
fun processNoBlur(outFbo: FloatFrameBuffer) {
|
||||
fun processNoBlur(outFbo: Float16FrameBuffer) {
|
||||
|
||||
blurtex0.dispose()
|
||||
|
||||
@@ -710,7 +711,7 @@ object IngameRenderer : Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
fun processKawaseBlur(outFbo: FloatFrameBuffer) {
|
||||
fun processKawaseBlur(outFbo: Float16FrameBuffer) {
|
||||
|
||||
blurtex0.dispose()
|
||||
|
||||
@@ -807,12 +808,12 @@ object IngameRenderer : Disposable {
|
||||
//fboBlurQuarter.dispose()
|
||||
}
|
||||
|
||||
fboRGB = FloatFrameBuffer(width, height, false)
|
||||
fboRGB_lightMixed = FloatFrameBuffer(width, height, false)
|
||||
fboA = FloatFrameBuffer(width, height, false)
|
||||
fboA_lightMixed = FloatFrameBuffer(width, height, false)
|
||||
fboMixedOut = FloatFrameBuffer(width, height, false)
|
||||
lightmapFbo = FloatFrameBuffer(
|
||||
fboRGB = Float16FrameBuffer(width, height, false)
|
||||
fboRGB_lightMixed = Float16FrameBuffer(width, height, false)
|
||||
fboA = Float16FrameBuffer(width, height, false)
|
||||
fboA_lightMixed = Float16FrameBuffer(width, height, false)
|
||||
fboMixedOut = Float16FrameBuffer(width, height, false)
|
||||
lightmapFbo = Float16FrameBuffer(
|
||||
LightmapRenderer.lightBuffer.width * LightmapRenderer.DRAW_TILE_SIZE.toInt(),
|
||||
LightmapRenderer.lightBuffer.height * LightmapRenderer.DRAW_TILE_SIZE.toInt(),
|
||||
false
|
||||
@@ -823,13 +824,13 @@ object IngameRenderer : Disposable {
|
||||
blurTex = TextureRegion()
|
||||
mixedOutTex = TextureRegion(fboMixedOut.colorBufferTexture)
|
||||
|
||||
fboBlurHalf = FloatFrameBuffer(
|
||||
fboBlurHalf = Float16FrameBuffer(
|
||||
LightmapRenderer.lightBuffer.width * LightmapRenderer.DRAW_TILE_SIZE.toInt() / 2,
|
||||
LightmapRenderer.lightBuffer.height * LightmapRenderer.DRAW_TILE_SIZE.toInt() / 2,
|
||||
false
|
||||
)
|
||||
|
||||
/*fboBlurQuarter = FloatFrameBuffer(
|
||||
/*fboBlurQuarter = Float16FrameBuffer(
|
||||
LightmapRenderer.lightBuffer.width * LightmapRenderer.DRAW_TILE_SIZE.toInt() / 4,
|
||||
LightmapRenderer.lightBuffer.height * LightmapRenderer.DRAW_TILE_SIZE.toInt() / 4,
|
||||
false
|
||||
|
||||
@@ -8,7 +8,7 @@ import com.badlogic.gdx.graphics.OrthographicCamera
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import com.badlogic.gdx.graphics.glutils.FloatFrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.Float16FrameBuffer
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.*
|
||||
@@ -147,7 +147,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
internal lateinit var uiRemoCon: UIRemoCon
|
||||
internal lateinit var uiFakeBlurOverlay: UICanvas
|
||||
|
||||
private lateinit var worldFBO: FloatFrameBuffer
|
||||
private lateinit var worldFBO: Float16FrameBuffer
|
||||
|
||||
private val warning32bitJavaIcon = TextureRegion(Texture(Gdx.files.internal("assets/graphics/gui/32_bit_warning.tga")))
|
||||
private val warningAppleRosettaIcon = TextureRegion(Texture(Gdx.files.internal("assets/graphics/gui/apple_rosetta_warning.tga")))
|
||||
@@ -166,12 +166,12 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
//ReadWorld.readWorldAndSetNewWorld(Terrarum.ingame!! as TerrarumIngame, reader)
|
||||
val world = ReadSimpleWorld(reader, file)
|
||||
demoWorld = world
|
||||
demoWorld.worldTime.timeDelta = 330 // a year = 8 minutes
|
||||
demoWorld.worldTime.timeDelta = 30
|
||||
printdbg(this, "Demo world loaded")
|
||||
}
|
||||
catch (e: IOException) {
|
||||
demoWorld = GameWorld(LandUtil.CHUNK_W, LandUtil.CHUNK_H, 0L, 0L)
|
||||
demoWorld.worldTime.timeDelta = 60
|
||||
demoWorld.worldTime.timeDelta = 30
|
||||
printdbg(this, "Demo world not found, using empty world")
|
||||
}
|
||||
|
||||
@@ -210,6 +210,8 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
|
||||
IngameRenderer.setRenderedWorld(demoWorld)
|
||||
WeatherMixer.internalReset()
|
||||
WeatherMixer.titleScreenInitWeather()
|
||||
|
||||
|
||||
// load a half-gradient texture that would be used throughout the titlescreen and its sub UIs
|
||||
@@ -262,7 +264,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
Gdx.input.inputProcessor = TitleScreenController(this)
|
||||
|
||||
|
||||
worldFBO = FloatFrameBuffer(App.scr.width, App.scr.height, false)
|
||||
worldFBO = Float16FrameBuffer(App.scr.width, App.scr.height, false)
|
||||
|
||||
// load list of savegames
|
||||
printdbg(this, "update list of savegames")
|
||||
@@ -285,20 +287,15 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
private val updateScreen = { delta: Float ->
|
||||
// TODO: desynched weather and time-of-day change
|
||||
|
||||
val forcedTime = 32880 // 9h08m
|
||||
demoWorld.globalLight = WeatherMixer.globalLightNow
|
||||
// demoWorld.globalLight = WeatherMixer.getGlobalLightOfTimeOfNoon()
|
||||
demoWorld.updateWorldTime(delta)
|
||||
// WeatherMixer.update(delta, cameraPlayer, demoWorld)
|
||||
WeatherMixer.forceTimeAt = forcedTime
|
||||
WeatherMixer.update(delta, cameraPlayer, demoWorld)
|
||||
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 //
|
||||
uiContainer.forEach { it?.update(delta) }
|
||||
}
|
||||
|
||||
@@ -14,16 +14,21 @@ import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
|
||||
*/
|
||||
internal object Inventory : ConsoleCommand {
|
||||
|
||||
private var targetID: ActorID = INGAME.actorNowPlaying?.referenceID ?: PLAYER_REF_ID
|
||||
private var targetID: ActorID = 0
|
||||
|
||||
private fun tryTargetActivePlayer() {
|
||||
targetID = INGAME.actorNowPlaying?.referenceID ?: 0
|
||||
}
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size == 1) {
|
||||
printUsage()
|
||||
}
|
||||
else if (args[1] == "target") {
|
||||
targetID = if (args[2].lowercase() == "player") (INGAME.actorNowPlaying?.referenceID ?: PLAYER_REF_ID) else args[2].toInt()
|
||||
if (args[2].lowercase() == "player") tryTargetActivePlayer() else targetID = args[2].toInt()
|
||||
}
|
||||
else {
|
||||
if (targetID == 0) tryTargetActivePlayer()
|
||||
val actor = getActor()
|
||||
if (actor != null) {
|
||||
when (args[1]) {
|
||||
@@ -36,7 +41,7 @@ internal object Inventory : ConsoleCommand {
|
||||
}
|
||||
}
|
||||
else {
|
||||
Echo("Actor $targetID is not Pocketed or does not exists")
|
||||
Echo("Actor $targetID is not Pocketed or does not exist")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
22
src/net/torvald/terrarum/modulebasegame/console/Uuid.kt
Normal file
22
src/net/torvald/terrarum/modulebasegame/console/Uuid.kt
Normal file
@@ -0,0 +1,22 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.INGAME
|
||||
import net.torvald.terrarum.ccG
|
||||
import net.torvald.terrarum.ccY
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-08-22.
|
||||
*/
|
||||
object Uuid : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
val worldUUID = INGAME.world.worldIndex
|
||||
val playerUUID = INGAME.actorGamer.uuid
|
||||
Echo("${ccY}World UUID: ${ccG}$worldUUID")
|
||||
Echo("${ccY}Player UUID: ${ccG}$playerUUID")
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.gameactors.*
|
||||
import net.torvald.terrarum.gameactors.faction.Faction
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
import net.torvald.terrarum.itemproperties.Material
|
||||
import net.torvald.terrarum.realestate.LandUtil
|
||||
import org.dyn4j.geometry.Vector2
|
||||
|
||||
@@ -116,6 +115,8 @@ open class ActorHumanoid : ActorWithBody, Controllable, Pocketed, Factionable, L
|
||||
|
||||
@Transient const val SPRITE_ROW_IDLE = 0
|
||||
@Transient const val SPRITE_ROW_WALK = 1
|
||||
|
||||
@Transient const val downDownMinLengthBase = 12
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@@ -173,7 +174,7 @@ open class ActorHumanoid : ActorWithBody, Controllable, Pocketed, Factionable, L
|
||||
|
||||
var isUpDown = false; protected set
|
||||
var isDownDown = false; protected set
|
||||
var downDownVirtually = false; internal set
|
||||
var downButtonHeld = 0; internal set
|
||||
var isLeftDown = false; protected set
|
||||
var isRightDown = false; protected set
|
||||
var isJumpDown = false; protected set
|
||||
@@ -221,7 +222,7 @@ open class ActorHumanoid : ActorWithBody, Controllable, Pocketed, Factionable, L
|
||||
if (isNoClip) {
|
||||
//grounded = true
|
||||
// platformToIgnore = null
|
||||
downDownVirtually = false
|
||||
downButtonHeld = 0
|
||||
}
|
||||
|
||||
// reset control box of AI
|
||||
@@ -248,13 +249,16 @@ open class ActorHumanoid : ActorWithBody, Controllable, Pocketed, Factionable, L
|
||||
}
|
||||
}
|
||||
|
||||
private val downDownMinLength: Int
|
||||
get() = (downDownMinLengthBase * (gravitation.y.abs() / 9.8).sqrt()).ceilToInt()
|
||||
|
||||
private fun updateGamerControlBox() {
|
||||
if (isGamer) {
|
||||
isUpDown = Gdx.input.isKeyPressed(App.getConfigInt("control_key_up"))
|
||||
isLeftDown = Gdx.input.isKeyPressed(App.getConfigInt("control_key_left"))
|
||||
isDownDown = Gdx.input.isKeyPressed(App.getConfigInt("control_key_down"))
|
||||
isRightDown = Gdx.input.isKeyPressed(App.getConfigInt("control_key_right"))
|
||||
isJumpDown = Gdx.input.isKeyPressed(App.getConfigInt("control_key_jump"))
|
||||
isUpDown = Gdx.input.isKeyPressed(ControlPresets.getKey("control_key_up"))
|
||||
isLeftDown = Gdx.input.isKeyPressed(ControlPresets.getKey("control_key_left"))
|
||||
isDownDown = Gdx.input.isKeyPressed(ControlPresets.getKey("control_key_down"))
|
||||
isRightDown = Gdx.input.isKeyPressed(ControlPresets.getKey("control_key_right"))
|
||||
isJumpDown = Gdx.input.isKeyPressed(ControlPresets.getKey("control_key_jump"))
|
||||
|
||||
val gamepad = App.gamepad
|
||||
|
||||
@@ -264,7 +268,7 @@ open class ActorHumanoid : ActorWithBody, Controllable, Pocketed, Factionable, L
|
||||
axisRX = gamepad.getAxis(App.getConfigInt("control_gamepad_axisrx"))
|
||||
axisRY = gamepad.getAxis(App.getConfigInt("control_gamepad_axisry"))
|
||||
|
||||
isJumpDown = Gdx.input.isKeyPressed(App.getConfigInt("control_key_jump")) ||
|
||||
isJumpDown = Gdx.input.isKeyPressed(ControlPresets.getKey("control_key_jump")) ||
|
||||
gamepad.getButton(App.getConfigInt("control_gamepad_ltrigger"))
|
||||
}
|
||||
|
||||
@@ -288,17 +292,14 @@ open class ActorHumanoid : ActorWithBody, Controllable, Pocketed, Factionable, L
|
||||
}
|
||||
|
||||
// platform-related hacks
|
||||
// allow latching down downDownVirtually only when standing on a platform AND not jumping upwards
|
||||
val occupyingTileHasPlatform = bodyTiles.filterNotNull().any { it.isPlatform }
|
||||
val feetTileHasPlatform = feetTiles.filterNotNull().any { it.isPlatform }
|
||||
val feetTileIsAllPlatform = feetTiles.filterNotNull().all { it.isPlatform }
|
||||
if (isDownDown && feetTileIsAllPlatform && (controllerV?.y ?: 0.0) >= 0.0) {// ||
|
||||
// occupyingTileHasPlatform && !feetTileHasPlatform) { // FIXME commenting this out enables platform-ladder but falldown gets slowed down if the body passes thru the platform but I think this behav might be beneficial for player?
|
||||
downDownVirtually = true
|
||||
if (isDownDown || downButtonHeld in 1 until downDownMinLength) {
|
||||
downButtonHeld += 1
|
||||
}
|
||||
if (downDownVirtually && !occupyingTileHasPlatform && !feetTileIsAllPlatform) {
|
||||
downDownVirtually = false
|
||||
else {
|
||||
downButtonHeld = 0
|
||||
}
|
||||
// TODO just disable "snap to ground" on collision solver if {player's body overlaps with the platform/downDownVirtually}?
|
||||
// the point is: disable snap (or don't consider offending tiles as solid) for certain Y-pos only, tiles on Y+1 are still solid
|
||||
}
|
||||
|
||||
private inline val hasController: Boolean
|
||||
@@ -347,11 +348,11 @@ open class ActorHumanoid : ActorWithBody, Controllable, Pocketed, Factionable, L
|
||||
// ↑F, ↓S
|
||||
if (isRightDown && !isLeftDown) {
|
||||
walkHorizontal(false, AXIS_KEYBOARD)
|
||||
prevHMoveKey = App.getConfigInt("control_key_right")
|
||||
prevHMoveKey = ControlPresets.getKey("control_key_right")
|
||||
} // ↓F, ↑S
|
||||
else if (isLeftDown && !isRightDown) {
|
||||
walkHorizontal(true, AXIS_KEYBOARD)
|
||||
prevHMoveKey = App.getConfigInt("control_key_left")
|
||||
prevHMoveKey = ControlPresets.getKey("control_key_left")
|
||||
} // ↓F, ↓S
|
||||
/*else if (isLeftDown && isRightDown) {
|
||||
if (prevHMoveKey == KeyMap.getKeyCode(EnumKeyFunc.MOVE_LEFT)) {
|
||||
@@ -375,11 +376,11 @@ open class ActorHumanoid : ActorWithBody, Controllable, Pocketed, Factionable, L
|
||||
// ↑E, ↓D
|
||||
if (isDownDown && !isUpDown) {
|
||||
walkVertical(false, AXIS_KEYBOARD)
|
||||
prevVMoveKey = App.getConfigInt("control_key_down")
|
||||
prevVMoveKey = ControlPresets.getKey("control_key_down")
|
||||
} // ↓E, ↑D
|
||||
else if (isUpDown && !isDownDown) {
|
||||
walkVertical(true, AXIS_KEYBOARD)
|
||||
prevVMoveKey = App.getConfigInt("control_key_up")
|
||||
prevVMoveKey = ControlPresets.getKey("control_key_up")
|
||||
} // ↓E, ↓D
|
||||
/*else if (isUpDown && isDownDown) {
|
||||
if (prevVMoveKey == KeyMap.getKeyCode(EnumKeyFunc.MOVE_UP)) {
|
||||
|
||||
@@ -248,7 +248,7 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
|
||||
forEachBlockbox { x, y, _, _ ->
|
||||
if (!hasCollision) {
|
||||
val tile = world!!.getTileFromTerrain(x, y)
|
||||
if (BlockCodex[tile].isSolid || BlockCodex[tile].isActorBlock) {
|
||||
if (!BlockCodex[tile].hasTag("INCONSEQUENTIAL")) {
|
||||
hasCollision = true
|
||||
}
|
||||
}
|
||||
@@ -311,7 +311,7 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
|
||||
forEachBlockbox { x, y, _, _ ->
|
||||
if (!hasCollision) {
|
||||
val tile = world!!.getTileFromTerrain(x, y)
|
||||
if (BlockCodex[tile].isSolid || BlockCodex[tile].isActorBlock) {
|
||||
if (!BlockCodex[tile].hasTag("INCONSEQUENTIAL")) {
|
||||
hasCollision = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.INGAME
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.gameactors.AVKey
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIWallCalendar
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-08-08.
|
||||
*/
|
||||
class FixtureWallCalendar : FixtureBase {
|
||||
|
||||
constructor() : super(
|
||||
BlockBox(BlockBox.NO_COLLISION, 1, 1),
|
||||
nameFun = { Lang["ITEM_CALENDAR"] },
|
||||
mainUI = UIWallCalendar()
|
||||
) {
|
||||
val itemImage = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/calendar.tga")
|
||||
|
||||
density = 600.0
|
||||
setHitboxDimension(TILE_SIZE, TILE_SIZE, 0, 1)
|
||||
|
||||
makeNewSprite(TextureRegionPack(itemImage.texture, TILE_SIZE, TILE_SIZE)).let {
|
||||
it.setRowsAndFrames(1,1)
|
||||
}
|
||||
|
||||
actorValue[AVKey.BASEMASS] = 1.0
|
||||
}
|
||||
|
||||
override var tooltipText: String?
|
||||
get() = Lang.getAndUseTemplate("CONTEXT_CALENDAR_DATE_FORMAT_YMD_DDD", false,
|
||||
world!!.worldTime.years,
|
||||
world!!.worldTime.getMonthNameFull(),
|
||||
world!!.worldTime.calendarDay,
|
||||
world!!.worldTime.getDayNameFull()
|
||||
)//INGAME.world.worldTime.getFormattedCalendarDay()
|
||||
set(value) {}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ object BlockBase {
|
||||
|
||||
// return false if there is a "solid" tile already
|
||||
if (isWall && BlockCodex[wallUnderCursor].isSolid ||
|
||||
!isWall && (BlockCodex[terrainUnderCursor].isSolid || BlockCodex[terrainUnderCursor].isActorBlock))
|
||||
!isWall && !BlockCodex[terrainUnderCursor].hasTag("INCONSEQUENTIAL"))
|
||||
return@mouseInInteractableRange -1L
|
||||
|
||||
// filter passed, do the job
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameitems
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-08-08.
|
||||
*/
|
||||
class ItemWallCalendar(originalID: ItemID) : FixtureItemBase(originalID, "net.torvald.terrarum.modulebasegame.gameactors.FixtureWallCalendar") {
|
||||
|
||||
override var dynamicID: ItemID = originalID
|
||||
override val originalName = "ITEM_CALENDAR"
|
||||
override var baseMass = 1.0
|
||||
override var stackable = true
|
||||
override var inventoryCategory = Category.MISC
|
||||
override val isUnique = false
|
||||
override val isDynamic = false
|
||||
override val materialId = ""
|
||||
override val itemImage: TextureRegion
|
||||
get() = getItemImageFromSingleImage("basegame", "sprites/fixtures/calendar.tga")
|
||||
|
||||
override var baseToolSize: Double? = baseMass
|
||||
|
||||
init {
|
||||
equipPosition = EquipPosition.HAND_GRIP
|
||||
}
|
||||
|
||||
}
|
||||
@@ -133,7 +133,7 @@ class QuickSingleplayerWorldSavingThread(
|
||||
|
||||
// Write Actors //
|
||||
actorsList.forEachIndexed { count, it ->
|
||||
printdbg(this, "Writing actors... ${count+1}/${actorsList.size}")
|
||||
printdbg(this, "Writing actors... ${count+1}/${actorsList.size} (${it.javaClass.canonicalName})")
|
||||
|
||||
val actorContent = EntryFile(WriteActor.encodeToByteArray64(it))
|
||||
val actor = DiskEntry(it.referenceID.toLong(), ROOT, creation_t, time_t, actorContent)
|
||||
|
||||
@@ -56,10 +56,10 @@ object ControlPanelCommon {
|
||||
|
||||
val initialSel = optionsList.indexOf(App.getConfigString(optionName))
|
||||
|
||||
println("labelFuns = ${labelFuns.map { it.invoke() }}")
|
||||
println("optionsList = $optionsList")
|
||||
println("optionName = $optionName; value = ${App.getConfigString(optionName)}")
|
||||
println("initialSel = $initialSel")
|
||||
// println("labelFuns = ${labelFuns.map { it.invoke() }}")
|
||||
// println("optionsList = $optionsList")
|
||||
// println("optionName = $optionName; value = ${App.getConfigString(optionName)}")
|
||||
// println("initialSel = $initialSel")
|
||||
|
||||
if (initialSel < 0) throw IllegalArgumentException("config value '${App.getConfigString(optionName)}' for option '$optionName' is not found on the options list")
|
||||
|
||||
@@ -69,6 +69,19 @@ object ControlPanelCommon {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (args.startsWith("spinnersel,")) {
|
||||
val labelFuns = arg.subList(1, arg.size).map { { it } }
|
||||
val optionsList = arg.subList(1, arg.size).map { it.toInt() }
|
||||
|
||||
val initialSel = optionsList.indexOf(App.getConfigInt(optionName))
|
||||
if (initialSel < 0) throw IllegalArgumentException("config value '${App.getConfigInt(optionName)}' for option '$optionName' is not found on the options list")
|
||||
|
||||
UIItemTextSelector(parent, x, y, labelFuns, initialSel, CONFIG_SPINNER_WIDTH, clickToShowPalette = false, useSpinnerButtons = true) to { it: UIItem, optionStr: String ->
|
||||
(it as UIItemTextSelector).selectionChangeListener = {
|
||||
App.setConfig(optionStr, optionsList[it])
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (args.startsWith("spinner,")) {
|
||||
UIItemSpinner(parent, x, y, App.getConfigInt(optionName), arg[1].toInt(), arg[2].toInt(), arg[3].toInt(), CONFIG_SPINNER_WIDTH, numberToTextFunction = { "${it.toLong()}" }) to { it: UIItem, optionStr: String ->
|
||||
(it as UIItemSpinner).selectionChangeListener = {
|
||||
|
||||
@@ -17,6 +17,10 @@ import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
*/
|
||||
class UIBasicInfo() : UICanvas() {
|
||||
|
||||
init {
|
||||
handler.allowESCtoClose = false
|
||||
}
|
||||
|
||||
val player: ActorHumanoid?
|
||||
get() = Terrarum.ingame?.actorNowPlaying
|
||||
|
||||
@@ -42,7 +46,7 @@ class UIBasicInfo() : UICanvas() {
|
||||
ELuptimer += delta
|
||||
}
|
||||
|
||||
if (mouseUp || Gdx.input.isKeyPressed(App.getConfigInt("control_key_interact"))) {
|
||||
if (mouseUp || Gdx.input.isKeyPressed(ControlPresets.getKey("control_key_interact"))) {
|
||||
ELuptimer = 0f
|
||||
ELon = true
|
||||
}
|
||||
|
||||
@@ -14,6 +14,10 @@ import net.torvald.terrarum.ui.UICanvas
|
||||
*/
|
||||
class UICheatDetected : UICanvas() {
|
||||
|
||||
init {
|
||||
handler.allowESCtoClose = false
|
||||
}
|
||||
|
||||
override var width: Int
|
||||
get() = App.scr.width
|
||||
set(value) { throw UnsupportedOperationException() }
|
||||
|
||||
@@ -78,7 +78,7 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
|
||||
|
||||
private val controlHelp: String
|
||||
get() = if (App.environment == RunningEnvironment.PC)
|
||||
"${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||
"${getKeycapPC(ControlPresets.getKey("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||
else
|
||||
"$gamepadLabelStart ${Lang["GAME_ACTION_CLOSE"]}\u3000 " +
|
||||
"$gamepadLabelLEFTRIGHT ${Lang["GAME_OBJECTIVE_MULTIPLIER"]}\u3000 " +
|
||||
@@ -125,7 +125,7 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
|
||||
// If the player has the required item, use it; otherwise, will take an item from the ItemCodex
|
||||
player.itemList.filter { (itm, qty) ->
|
||||
ItemCodex[itm]?.tags?.contains(ingredient.key) == true && qty >= ingredient.qty
|
||||
}.maxByOrNull { it.qty }?.itm ?: ((ItemCodex.itemCodex.firstNotNullOfOrNull { if (it.value.tags.contains(ingredient.key)) it.key else null }) ?: throw NullPointerException("Item with tag '${ingredient.key}' not found. Possible cause: game or a module not updated or installed"))
|
||||
}.maxByOrNull { it.qty }?.itm ?: ((ItemCodex.itemCodex.firstNotNullOfOrNull { if (it.value.hasTag(ingredient.key)) it.key else null }) ?: throw NullPointerException("Item with tag '${ingredient.key}' not found. Possible cause: game or a module not updated or installed"))
|
||||
}
|
||||
else {
|
||||
ingredient.key
|
||||
@@ -234,7 +234,7 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
|
||||
// don't rely on highlightedness of the button to determine the item on the button is the selected
|
||||
// ingredient (because I don't fully trust my code lol)
|
||||
val targetItemToAlter = recipe.ingredients.filter { // altering recipe doesn't make sense if player selected a recipe that requires no tag-ingredients
|
||||
(it.keyMode == CraftingCodex.CraftingItemKeyMode.TAG && gameItem.tags.contains(it.key))
|
||||
(it.keyMode == CraftingCodex.CraftingItemKeyMode.TAG && gameItem.hasTag(it.key))
|
||||
}.let {
|
||||
if (it.size > 1)
|
||||
println("[UICrafting] Your recipe seems to have two similar ingredients defined\n" +
|
||||
@@ -245,7 +245,7 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
|
||||
|
||||
targetItemToAlter?.let {
|
||||
val oldItem = _getItemListIngredients().getInventory().itemList.first { itemPair ->
|
||||
(it.keyMode == CraftingCodex.CraftingItemKeyMode.TAG && ItemCodex[itemPair.itm]!!.tags.contains(it.key))
|
||||
(it.keyMode == CraftingCodex.CraftingItemKeyMode.TAG && ItemCodex[itemPair.itm]!!.hasTag(it.key))
|
||||
}
|
||||
changeIngredient(oldItem, itemID)
|
||||
refreshCraftButtonStatus()
|
||||
@@ -279,7 +279,7 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
|
||||
// If the player has the required item, use it; otherwise, will take an item from the ItemCodex
|
||||
val selectedItem = playerInventory.itemList.filter { (itm, qty) ->
|
||||
ItemCodex[itm]?.tags?.contains(ingredient.key) == true && qty >= ingredient.qty
|
||||
}.maxByOrNull { it.qty }?.itm ?: ((ItemCodex.itemCodex.firstNotNullOfOrNull { if (it.value.tags.contains(ingredient.key)) it.key else null }) ?: throw NullPointerException("Item with tag '${ingredient.key}' not found. Possible cause: game or a module not updated or installed"))
|
||||
}.maxByOrNull { it.qty }?.itm ?: ((ItemCodex.itemCodex.firstNotNullOfOrNull { if (it.value.hasTag(ingredient.key)) it.key else null }) ?: throw NullPointerException("Item with tag '${ingredient.key}' not found. Possible cause: game or a module not updated or installed"))
|
||||
|
||||
// printdbg(this, "Adding ingredients by tag ${selectedItem} (${ingredient.qty})")
|
||||
selectedItem
|
||||
|
||||
@@ -24,18 +24,18 @@ class UIGraphicsControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
||||
init {
|
||||
ControlPanelCommon.register(this, width, "basegame.graphicscontrolpanel", arrayOf(
|
||||
arrayOf("", { Lang["CREDITS_VFX"] }, "h1"),
|
||||
arrayOf("fx_dither", { Lang["MENU_OPTIONS_DITHER"] }, "toggle"),
|
||||
arrayOf("fx_backgroundblur", { Lang["MENU_OPTIONS_BLUR"] }, "toggle"),
|
||||
arrayOf("maxparticles", { Lang["MENU_OPTIONS_PARTICLES"] }, "spinner,256,1024,256"),
|
||||
arrayOf("fx_dither", { Lang["MENU_OPTIONS_DITHER"] }, "toggle"),
|
||||
arrayOf("fx_backgroundblur", { Lang["MENU_OPTIONS_BLUR"] }, "toggle"),
|
||||
arrayOf("maxparticles", { Lang["MENU_OPTIONS_PARTICLES"] }, "spinner,256,1024,256"),
|
||||
arrayOf("", { Lang["MENU_OPTIONS_DISPLAY"] }, "h1"),
|
||||
arrayOf("screenwidth,screenheight", { Lang["MENU_OPTIONS_RESOLUTION"] }, "typeinres"),
|
||||
arrayOf("screenmagnifying", { Lang["GAME_ACTION_ZOOM"] }, "spinnerd,1.0,2.0,0.05"),
|
||||
arrayOf("screenmagnifyingfilter", { Lang["MENU_OPTIONS_FILTERING_MODE"] }, "textsel,none=MENU_OPTIONS_NONE,bilinear=MENU_OPTIONS_FILTERING_BILINEAR,hq2x=MENU_OPTIONS_FILTERING_HQ2X_DNT"),
|
||||
arrayOf("displayfps", { Lang["MENU_LABEL_FRAMESPERSEC"] }, "spinner,0,300,2"),
|
||||
arrayOf("usevsync", { Lang["MENU_OPTIONS_VSYNC"] }, "toggle"),
|
||||
arrayOf("", { "(${Lang["MENU_LABEL_RESTART_REQUIRED"]})" }, "p"),
|
||||
arrayOf("screenwidth,screenheight", { Lang["MENU_OPTIONS_RESOLUTION"] }, "typeinres"),
|
||||
arrayOf("screenmagnifying", { Lang["GAME_ACTION_ZOOM"] }, "spinnerd,1.0,2.0,0.05"),
|
||||
arrayOf("screenmagnifyingfilter", { Lang["MENU_OPTIONS_FILTERING_MODE"] }, "textsel,none=MENU_OPTIONS_NONE,bilinear=MENU_OPTIONS_FILTERING_BILINEAR,hq2x=MENU_OPTIONS_FILTERING_HQ2X_DNT"),
|
||||
arrayOf("displayfps", { Lang["MENU_LABEL_FRAMESPERSEC"] }, "spinner,0,300,2"),
|
||||
arrayOf("usevsync", { Lang["MENU_OPTIONS_VSYNC"] }, "toggle"),
|
||||
arrayOf("", { "(${Lang["MENU_LABEL_RESTART_REQUIRED"]})" }, "p"),
|
||||
arrayOf("", { Lang["MENU_LABEL_STREAMING"] }, "h1"),
|
||||
arrayOf("fx_streamerslayout", { Lang["MENU_OPTIONS_STREAMERS_LAYOUT"] }, "toggle"),
|
||||
arrayOf("fx_streamerslayout", { Lang["MENU_OPTIONS_STREAMERS_LAYOUT"] }, "toggle"),
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.unicode.EMDASH
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.CommonResourcePool
|
||||
import net.torvald.terrarum.ControlPresets
|
||||
import net.torvald.terrarum.gamecontroller.*
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.linearSearch
|
||||
@@ -318,7 +319,7 @@ private class UIItemInputKeycap(
|
||||
else if (parent.shiftin && keysymsLow[1]?.isNotEmpty() == true) keysymsLow[1]
|
||||
else keysymsLow[0]) ?: ""
|
||||
|
||||
val keysym0: Array<String?> = if (KeyToggler.isOn(App.getConfigInt("control_key_toggleime"))) {
|
||||
val keysym0: Array<String?> = if (KeyToggler.isOn(ControlPresets.getKey("control_key_toggleime"))) {
|
||||
if (parent.highlayer == null) arrayOf(keysymLow,keysymLow,keysymLow,keysymLow)
|
||||
else {
|
||||
val keysyms = parent.highlayer!!.config.symbols
|
||||
|
||||
161
src/net/torvald/terrarum/modulebasegame/ui/UIImportAvatar.kt
Normal file
161
src/net/torvald/terrarum/modulebasegame/ui/UIImportAvatar.kt
Normal file
@@ -0,0 +1,161 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.ceilToInt
|
||||
import net.torvald.terrarum.gamecontroller.*
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.serialise.Ascii85Codec
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
import net.torvald.terrarum.ui.UIItem
|
||||
import net.torvald.terrarum.ui.UIItemTextButton
|
||||
import net.torvald.terrarum.utils.Clipboard
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-08-24.
|
||||
*/
|
||||
class UIImportAvatar(val remoCon: UIRemoCon) : Advanceable() {
|
||||
|
||||
override var width = 480 // SAVE_CELL_WIDTH
|
||||
override var height = 480
|
||||
override var openCloseTime: Second = OPENCLOSE_GENERIC
|
||||
|
||||
private val drawX = (Toolkit.drawWidth - width) / 2
|
||||
private val drawY = (App.scr.height - height) / 2
|
||||
private val cols = 80
|
||||
private val rows = 30
|
||||
private val goButtonWidth = 180
|
||||
|
||||
|
||||
private val codeBox = UIItemCodeBox(this, (Toolkit.drawWidth - App.fontSmallNumbers.W * cols) / 2, drawY, cols, rows)
|
||||
|
||||
private val clearButton = UIItemTextButton(this,
|
||||
{ Lang["MENU_IO_CLEAR"] }, drawX + (width/2 - goButtonWidth) / 2, drawY + height - 24 - 34, goButtonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
|
||||
private val pasteButton = UIItemTextButton(this,
|
||||
{ Lang["MENU_LABEL_PASTE"] }, drawX + width/2 + (width/2 - goButtonWidth) / 2, drawY + height - 24 - 34, goButtonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
|
||||
|
||||
|
||||
private val backButton = UIItemTextButton(this,
|
||||
{ Lang["MENU_LABEL_BACK"] }, drawX + (width/2 - goButtonWidth) / 2, drawY + height - 24, goButtonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
|
||||
private val goButton = UIItemTextButton(this,
|
||||
{ Lang["MENU_IO_IMPORT"] }, drawX + width/2 + (width/2 - goButtonWidth) / 2, drawY + height - 24, goButtonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
|
||||
|
||||
init {
|
||||
addUIitem(codeBox)
|
||||
addUIitem(clearButton)
|
||||
addUIitem(pasteButton)
|
||||
addUIitem(backButton)
|
||||
addUIitem(goButton)
|
||||
|
||||
clearButton.clickOnceListener = { _,_ ->
|
||||
codeBox.clearTextBuffer()
|
||||
}
|
||||
pasteButton.clickOnceListener = { _,_ ->
|
||||
codeBox.pasteFromClipboard()
|
||||
}
|
||||
backButton.clickOnceListener = { _,_ ->
|
||||
remoCon.openUI(UILoadSavegame(remoCon))
|
||||
}
|
||||
goButton.clickOnceListener = { _,_ ->
|
||||
doImport()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun updateUI(delta: Float) {
|
||||
uiItems.forEach { it.update(delta) }
|
||||
}
|
||||
|
||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||
uiItems.forEach { it.render(batch, camera) }
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
}
|
||||
|
||||
override fun advanceMode(button: UIItem) {
|
||||
}
|
||||
|
||||
private fun doImport() {
|
||||
val rawStr = codeBox.textBuffer.toString()
|
||||
// sanity check
|
||||
|
||||
|
||||
val ascii85codec = Ascii85Codec((33..117).map { it.toChar() }.joinToString(""))
|
||||
val ascii85str = rawStr.substring(2 until rawStr.length - 2).replace("z", "!!!!!")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class UIItemCodeBox(parent: UIImportAvatar, initialX: Int, initialY: Int, val cols: Int = 80, val rows: Int = 24) : UIItem(parent, initialX, initialY) {
|
||||
|
||||
override val width = App.fontSmallNumbers.W * cols
|
||||
override val height = App.fontSmallNumbers.H * rows
|
||||
override fun dispose() {
|
||||
}
|
||||
|
||||
private var highlightCol: Color = Toolkit.Theme.COL_INACTIVE
|
||||
|
||||
var selected = false
|
||||
|
||||
private var textCursorPosition = 0
|
||||
internal var textBuffer = StringBuilder()
|
||||
|
||||
fun pasteFromClipboard() {
|
||||
textBuffer.clear()
|
||||
Clipboard.fetch().forEach {
|
||||
if (it.code in 33..122) textBuffer.append(it)
|
||||
}
|
||||
textCursorPosition += textBuffer.length
|
||||
}
|
||||
|
||||
override fun update(delta: Float) {
|
||||
super.update(delta)
|
||||
// if (!selected && mousePushed)
|
||||
// selected = true
|
||||
// else if (selected && mouseDown && !mouseUp)
|
||||
// selected = false
|
||||
|
||||
if (textBuffer.isEmpty() && (Gdx.input.isKeyJustPressed(Input.Keys.V) && (Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT) || Gdx.input.isKeyPressed(Input.Keys.CONTROL_RIGHT)))) {
|
||||
pasteFromClipboard()
|
||||
}
|
||||
}
|
||||
|
||||
override fun render(batch: SpriteBatch, camera: Camera) {
|
||||
// draw box backgrounds
|
||||
batch.color = UIInventoryFull.CELL_COL
|
||||
Toolkit.fillArea(batch, posX, posY, width, height)
|
||||
|
||||
// draw borders
|
||||
batch.color = if (selected) Toolkit.Theme.COL_SELECTED else if (mouseUp) Toolkit.Theme.COL_MOUSE_UP else Toolkit.Theme.COL_INACTIVE
|
||||
Toolkit.drawBoxBorder(batch, posX - 1, posY - 1, width + 2, height + 2)
|
||||
|
||||
// draw texts
|
||||
if (textBuffer.isEmpty()) {
|
||||
batch.color = Toolkit.Theme.COL_INACTIVE
|
||||
App.fontGame.draw(batch, Lang["CONTEXT_IMPORT_AVATAR_INSTRUCTION_1"], posX + 5, posY)
|
||||
App.fontGame.draw(batch, Lang["CONTEXT_IMPORT_AVATAR_INSTRUCTION_2"], posX + 5f, posY + App.fontGame.lineHeight)
|
||||
}
|
||||
else {
|
||||
batch.color = Color.WHITE
|
||||
val scroll = ((textBuffer.length.toDouble() / cols).ceilToInt() - rows).coerceAtLeast(0)
|
||||
for (i in scroll * cols until textBuffer.length) {
|
||||
val c = textBuffer[i]
|
||||
val x = ((i - scroll * cols) % cols) * App.fontSmallNumbers.W.toFloat()
|
||||
val y = ((i - scroll * cols) / cols) * App.fontSmallNumbers.H.toFloat()
|
||||
|
||||
App.fontSmallNumbers.draw(batch, "$c", posX + x, posY + y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun clearTextBuffer() {
|
||||
textBuffer.clear()
|
||||
textCursorPosition = 0
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package net.torvald.terrarum.modulebasegame.ui
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.App.*
|
||||
@@ -19,7 +18,7 @@ import net.torvald.unicode.*
|
||||
* Created by minjaesong on 2017-10-21.
|
||||
*/
|
||||
class UIInventoryFull(
|
||||
toggleKeyLiteral: Int? = App.getConfigInt("control_key_inventory"), toggleButtonLiteral: Int? = App.getConfigInt("control_gamepad_start"),
|
||||
toggleKeyLiteral: String? = "control_key_inventory", toggleButtonLiteral: String? = "control_gamepad_start",
|
||||
// UI positions itself? (you must g.flush() yourself after the g.translate(Int, Int))
|
||||
customPositioning: Boolean = false, // mainly used by vital meter
|
||||
doNotWarnConstant: Boolean = false
|
||||
@@ -157,16 +156,15 @@ class UIInventoryFull(
|
||||
//val INVENTORY_CELLS_OFFSET_Y: Int = 107 + (AppLoader.terrarumAppConfig.screenH - internalHeight) / 2
|
||||
|
||||
init {
|
||||
handler.allowESCtoClose = true
|
||||
}
|
||||
|
||||
private val SP = "\u3000 "
|
||||
val listControlHelp: String
|
||||
get() = if (App.environment == RunningEnvironment.PC)
|
||||
"${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}$SP" +
|
||||
"${getKeycapPC(ControlPresets.getKey("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}$SP" +
|
||||
"$KEYCAP_LEFT_MOUSE ${Lang["GAME_INVENTORY_USE"]}$SP" +
|
||||
"$KEYCAP_1$ENDASH\u2009$KEYCAP_0 ${Lang["GAME_INVENTORY_REGISTER"]}$SP" +
|
||||
"${getKeycapPC(App.getConfigInt("control_key_discard"))} ${Lang["GAME_INVENTORY_DROP"]}"
|
||||
"${getKeycapPC(ControlPresets.getKey("control_key_discard"))} ${Lang["GAME_INVENTORY_DROP"]}"
|
||||
else
|
||||
"$gamepadLabelStart ${Lang["GAME_ACTION_CLOSE"]}$SP" +
|
||||
"$gamepadLabelLT ${Lang["CONTEXT_ITEM_MAP"]}$SP" +
|
||||
@@ -176,7 +174,7 @@ class UIInventoryFull(
|
||||
"$gamepadLabelEast ${Lang["GAME_INVENTORY_DROP"]}"
|
||||
val minimapControlHelp: String
|
||||
get() = if (App.environment == RunningEnvironment.PC)
|
||||
"${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}$SP" +
|
||||
"${getKeycapPC(ControlPresets.getKey("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}$SP" +
|
||||
"$KEYCAP_LEFT_MOUSE$KEYCAP_MOVE ${Lang["GAME_ACTION_MOVE_VERB"]}"
|
||||
else
|
||||
"$gamepadLabelStart ${Lang["GAME_ACTION_CLOSE"]}$SP" +
|
||||
@@ -184,7 +182,7 @@ class UIInventoryFull(
|
||||
"$gamepadLabelRT ${Lang["GAME_INVENTORY"]}"
|
||||
val gameMenuControlHelp: String
|
||||
get() = if (App.environment == RunningEnvironment.PC)
|
||||
"${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||
"${getKeycapPC(ControlPresets.getKey("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||
else
|
||||
"$gamepadLabelStart ${Lang["GAME_ACTION_CLOSE"]}$SP" +
|
||||
"$gamepadLabelLT ${Lang["GAME_INVENTORY"]}"
|
||||
@@ -250,7 +248,7 @@ class UIInventoryFull(
|
||||
}
|
||||
|
||||
// allow "control_key_gamemenu" to open this UI and bring system menu immediately
|
||||
this.handler.toggleKeyExtra.add { App.getConfigInt("control_key_gamemenu") }
|
||||
this.handler.toggleKeyExtra.add("control_key_gamemenu" )
|
||||
this.handler.toggleKeyExtraAction.add {
|
||||
if (it.isClosed) {
|
||||
INGAME.setTooltipMessage(null)
|
||||
@@ -264,7 +262,7 @@ class UIInventoryFull(
|
||||
}
|
||||
|
||||
// allow "control_key_crafting" to open this UI and bring system menu immediately
|
||||
this.handler.toggleKeyExtra.add { App.getConfigInt("control_key_crafting") }
|
||||
this.handler.toggleKeyExtra.add("control_key_crafting")
|
||||
this.handler.toggleKeyExtraAction.add {
|
||||
if (it.isClosed) {
|
||||
INGAME.setTooltipMessage(null)
|
||||
|
||||
@@ -6,9 +6,7 @@ import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.CommonResourcePool
|
||||
import net.torvald.terrarum.DefaultConfig
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.ui.*
|
||||
|
||||
@@ -37,16 +35,16 @@ class UIKeyboardControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
||||
|
||||
private val keycaps = hashMapOf(
|
||||
Input.Keys.GRAVE to UIItemKeycap(this, 1, 1, null, oneu, ""),
|
||||
Input.Keys.NUM_1 to UIItemKeycap(this, 33,1, Input.Keys.NUM_1, oneu, "1,3"),
|
||||
Input.Keys.NUM_2 to UIItemKeycap(this, 65,1, Input.Keys.NUM_2, oneu, "2,3"),
|
||||
Input.Keys.NUM_3 to UIItemKeycap(this, 97,1, Input.Keys.NUM_3, oneu, "3,3"),
|
||||
Input.Keys.NUM_4 to UIItemKeycap(this, 129,1, Input.Keys.NUM_4, oneu, "4,3"),
|
||||
Input.Keys.NUM_5 to UIItemKeycap(this, 161,1, Input.Keys.NUM_5, oneu, "5,3"),
|
||||
Input.Keys.NUM_6 to UIItemKeycap(this, 193,1, Input.Keys.NUM_6, oneu, "6,3"),
|
||||
Input.Keys.NUM_7 to UIItemKeycap(this, 225,1, Input.Keys.NUM_7, oneu, "7,3"),
|
||||
Input.Keys.NUM_8 to UIItemKeycap(this, 257,1, Input.Keys.NUM_8, oneu, "8,3"),
|
||||
Input.Keys.NUM_9 to UIItemKeycap(this, 289,1, Input.Keys.NUM_9, oneu, "9,3"),
|
||||
Input.Keys.NUM_0 to UIItemKeycap(this, 321,1, Input.Keys.NUM_0, oneu, "0,3"),
|
||||
Input.Keys.NUM_1 to UIItemKeycap(this, 33,1, null, oneu, "1,3"),
|
||||
Input.Keys.NUM_2 to UIItemKeycap(this, 65,1, null, oneu, "2,3"),
|
||||
Input.Keys.NUM_3 to UIItemKeycap(this, 97,1, null, oneu, "3,3"),
|
||||
Input.Keys.NUM_4 to UIItemKeycap(this, 129,1, null, oneu, "4,3"),
|
||||
Input.Keys.NUM_5 to UIItemKeycap(this, 161,1, null, oneu, "5,3"),
|
||||
Input.Keys.NUM_6 to UIItemKeycap(this, 193,1, null, oneu, "6,3"),
|
||||
Input.Keys.NUM_7 to UIItemKeycap(this, 225,1, null, oneu, "7,3"),
|
||||
Input.Keys.NUM_8 to UIItemKeycap(this, 257,1, null, oneu, "8,3"),
|
||||
Input.Keys.NUM_9 to UIItemKeycap(this, 289,1, null, oneu, "9,3"),
|
||||
Input.Keys.NUM_0 to UIItemKeycap(this, 321,1, null, oneu, "0,3"),
|
||||
Input.Keys.MINUS to UIItemKeycap(this, 353,1, Input.Keys.MINUS, oneu, "10,3"),
|
||||
Input.Keys.EQUALS to UIItemKeycap(this, 385,1, Input.Keys.EQUALS, oneu, "11,3"),
|
||||
Input.Keys.BACKSPACE to UIItemKeycap(this, 417,1, Input.Keys.BACKSPACE, 60, "24,5"),
|
||||
@@ -105,25 +103,39 @@ class UIKeyboardControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
||||
) // end of keycaps
|
||||
|
||||
private val resetButtonWidth = 140
|
||||
private val buttonReset = UIItemTextButton(this,
|
||||
private val presetButtonWidth = 200
|
||||
/*private val buttonReset = UIItemTextButton(this,
|
||||
{ Lang["MENU_LABEL_RESET"] },
|
||||
kbx + (width - resetButtonWidth) / 2,
|
||||
kby + 162 + 12,
|
||||
kby + 162 + 16,
|
||||
resetButtonWidth,
|
||||
hasBorder = true,
|
||||
alignment = UIItemTextButton.Companion.Alignment.CENTRE
|
||||
)*/
|
||||
private val presetSelector = UIItemTextSelector(this,
|
||||
kbx + (width - presetButtonWidth) / 2,
|
||||
kby + 162 + 16,
|
||||
ControlPresets.presetLabels.map { { it } },
|
||||
ControlPresets.presetLabels.indexOf(App.getConfigString("control_preset_keyboard")),
|
||||
presetButtonWidth,
|
||||
clickToShowPalette = false,
|
||||
)
|
||||
|
||||
private val controlPalette = UIItemControlPaletteBaloon(this, (Toolkit.drawWidth - 500) / 2, kby + 219)
|
||||
private val controlPalette = UIItemControlPaletteBaloon(this, (Toolkit.drawWidth - 500) / 2, kby + 227)
|
||||
|
||||
init {
|
||||
|
||||
keycaps.values.forEach { addUIitem(it) }
|
||||
updateKeycaps()
|
||||
|
||||
buttonReset.clickOnceListener = { x, y ->
|
||||
/*buttonReset.clickOnceListener = { x, y ->
|
||||
resetKeyConfig()
|
||||
updateKeycaps()
|
||||
}*/
|
||||
|
||||
presetSelector.selectionChangeListener = { index ->
|
||||
App.setConfig("control_preset_keyboard", ControlPresets.presetLabels[index])
|
||||
updateKeycaps()
|
||||
}
|
||||
|
||||
// addUIitem(keyboardLayoutSelection)
|
||||
@@ -152,18 +164,18 @@ class UIKeyboardControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
||||
private fun updateKeycaps() {
|
||||
keycaps.values.forEach { it.symbolControl = null }
|
||||
// read config and put icons. Item order irrelevant
|
||||
keycaps[App.getConfigInt("control_key_up")]?.symbolControl = Keebsym.UP
|
||||
keycaps[App.getConfigInt("control_key_left")]?.symbolControl = Keebsym.LEFT
|
||||
keycaps[App.getConfigInt("control_key_down")]?.symbolControl = Keebsym.DOWN
|
||||
keycaps[App.getConfigInt("control_key_right")]?.symbolControl = Keebsym.RIGHT
|
||||
keycaps[App.getConfigInt("control_key_jump")]?.symbolControl = Keebsym.JUMP
|
||||
keycaps[App.getConfigInt("control_key_zoom")]?.symbolControl = Keebsym.ZOOM
|
||||
keycaps[App.getConfigInt("control_key_inventory")]?.symbolControl = Keebsym.INVENTORY
|
||||
keycaps[App.getConfigInt("control_key_movementaux")]?.symbolControl = Keebsym.HOOK
|
||||
keycaps[App.getConfigInt("control_key_quicksel")]?.symbolControl = Keebsym.PIE
|
||||
keycaps[App.getConfigInt("control_key_gamemenu")]?.symbolControl = Keebsym.MENU
|
||||
keycaps[App.getConfigInt("control_key_toggleime")]?.symbolControl = Keebsym.IME()
|
||||
keycaps[App.getConfigInt("control_key_crafting")]?.symbolControl = Keebsym.CRAFTING
|
||||
keycaps[ControlPresets.getKey("control_key_up")]?.symbolControl = Keebsym.UP
|
||||
keycaps[ControlPresets.getKey("control_key_left")]?.symbolControl = Keebsym.LEFT
|
||||
keycaps[ControlPresets.getKey("control_key_down")]?.symbolControl = Keebsym.DOWN
|
||||
keycaps[ControlPresets.getKey("control_key_right")]?.symbolControl = Keebsym.RIGHT
|
||||
keycaps[ControlPresets.getKey("control_key_jump")]?.symbolControl = Keebsym.JUMP
|
||||
keycaps[ControlPresets.getKey("control_key_zoom")]?.symbolControl = Keebsym.ZOOM
|
||||
keycaps[ControlPresets.getKey("control_key_inventory")]?.symbolControl = Keebsym.INVENTORY
|
||||
keycaps[ControlPresets.getKey("control_key_movementaux")]?.symbolControl = Keebsym.HOOK
|
||||
keycaps[ControlPresets.getKey("control_key_quicksel")]?.symbolControl = Keebsym.PIE
|
||||
keycaps[ControlPresets.getKey("control_key_gamemenu")]?.symbolControl = Keebsym.MENU
|
||||
keycaps[ControlPresets.getKey("control_key_toggleime")]?.symbolControl = Keebsym.IME()
|
||||
keycaps[ControlPresets.getKey("control_key_crafting")]?.symbolControl = Keebsym.CRAFTING
|
||||
}
|
||||
|
||||
internal var keycapClicked = -13372
|
||||
@@ -176,14 +188,14 @@ class UIKeyboardControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
||||
override fun updateUI(delta: Float) {
|
||||
uiItems.forEach {
|
||||
it.update(delta)
|
||||
if (it is UIItemKeycap && it.mousePushed) {
|
||||
if (it is UIItemKeycap && it.mousePushed && ControlPresets.presetLabels[presetSelector.selection] == "Custom") {
|
||||
it.selected = true
|
||||
// println("key ${it.key}; selected = ${it.selected}")
|
||||
keycapClicked = it.key ?: -13372
|
||||
}
|
||||
}
|
||||
|
||||
buttonReset.update(delta)
|
||||
presetSelector.update(delta)
|
||||
|
||||
controlPalette.update(delta)
|
||||
}
|
||||
@@ -194,7 +206,7 @@ class UIKeyboardControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
||||
// batch.color = fillCol
|
||||
// Toolkit.fillArea(batch, drawX, drawY, width, height)
|
||||
uiItems.forEach { it.render(batch, camera) }
|
||||
buttonReset.render(batch, camera)
|
||||
presetSelector.render(batch, camera)
|
||||
|
||||
// title
|
||||
// todo show "Keyboard"/"Gamepad" accordingly
|
||||
@@ -215,21 +227,56 @@ class UIKeyboardControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
||||
}
|
||||
|
||||
fun setControlOf(key: Int, control: Int) {
|
||||
if (App.getConfigString("control_preset_keyboard") != "Custom") {
|
||||
System.err.println("[UIKeyboardControlPanel] cannot set a control if the preset is not 'Custom' (current preset: ${App.getConfigString("control_preset_keyboard")})")
|
||||
return
|
||||
}
|
||||
if (control >= 0) {
|
||||
App.setConfig(UIItemControlPaletteBaloon.indexToConfigKey[control]!!, key)
|
||||
val controlName = UIItemControlPaletteBaloon.indexToConfigKey[control]!!
|
||||
|
||||
val conflicts = App.gameConfig.keySet.filter {
|
||||
(it as String).startsWith("control_key_")
|
||||
}.map {
|
||||
(it as String).let { it to
|
||||
try { (App.getConfigInt(it) == key) }
|
||||
catch (_: ClassCastException) { false }
|
||||
}
|
||||
}.filter { it.second }.map { it.first }.firstOrNull()
|
||||
|
||||
println("[UIKeyboardControlPanel] key=$key, control=$controlName")
|
||||
|
||||
if (conflicts != null) {
|
||||
val oldValue = App.getConfigInt(controlName)
|
||||
App.setConfig(conflicts, oldValue)
|
||||
|
||||
println("[UIKeyboardControlPanel] set config $conflicts=$oldValue")
|
||||
}
|
||||
|
||||
App.setConfig(controlName, key)
|
||||
println("[UIKeyboardControlPanel] set config $controlName=$key")
|
||||
}
|
||||
updateKeycaps()
|
||||
|
||||
Terrarum.ingame?.let {
|
||||
it.onConfigChange()
|
||||
}
|
||||
}
|
||||
|
||||
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
super.touchDown(screenX, screenY, pointer, button)
|
||||
buttonReset.touchDown(screenX, screenY, pointer, button)
|
||||
presetSelector.touchDown(screenX, screenY, pointer, button)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
super.touchUp(screenX, screenY, pointer, button)
|
||||
buttonReset.touchUp(screenX, screenY, pointer, button)
|
||||
presetSelector.touchUp(screenX, screenY, pointer, button)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun scrolled(amountX: Float, amountY: Float): Boolean {
|
||||
super.scrolled(amountX, amountY)
|
||||
presetSelector.scrolled(amountX, amountY)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ class UILoadDemoSavefiles(val remoCon: UIRemoCon) : Advanceable() {
|
||||
|
||||
private val controlHelp: String
|
||||
get() = if (App.environment == RunningEnvironment.PC)
|
||||
"${getKeycapPC(App.getConfigInt("control_key_up"))}${getKeycapPC(App.getConfigInt("control_key_down"))}" +
|
||||
"${getKeycapPC(ControlPresets.getKey("control_key_up"))}${getKeycapPC(ControlPresets.getKey("control_key_down"))}" +
|
||||
" ${Lang["MENU_CONTROLS_SCROLL"]}"
|
||||
else
|
||||
"${getKeycapConsole('R')} ${Lang["MENU_CONTROLS_SCROLL"]}"
|
||||
@@ -408,12 +408,12 @@ class UILoadDemoSavefiles(val remoCon: UIRemoCon) : Advanceable() {
|
||||
if (this.isVisible) {
|
||||
val cells = getCells()
|
||||
|
||||
if ((keycode == Input.Keys.UP || keycode == App.getConfigInt("control_key_up")) && scrollTarget > 0) {
|
||||
if ((keycode == Input.Keys.UP || keycode == ControlPresets.getKey("control_key_up")) && scrollTarget > 0) {
|
||||
scrollFrom = listScroll
|
||||
scrollTarget -= 1
|
||||
scrollAnimCounter = 0f
|
||||
}
|
||||
else if ((keycode == Input.Keys.DOWN || keycode == App.getConfigInt("control_key_down")) && scrollTarget < cells.size - savesVisible) {
|
||||
else if ((keycode == Input.Keys.DOWN || keycode == ControlPresets.getKey("control_key_down")) && scrollTarget < cells.size - savesVisible) {
|
||||
scrollFrom = listScroll
|
||||
scrollTarget += 1
|
||||
scrollAnimCounter = 0f
|
||||
|
||||
@@ -25,7 +25,7 @@ class UILoadList(val full: UILoadSavegame) : UICanvas() {
|
||||
|
||||
private val controlHelp: String
|
||||
get() = if (App.environment == RunningEnvironment.PC)
|
||||
"${getKeycapPC(App.getConfigInt("control_key_up"))}${getKeycapPC(App.getConfigInt("control_key_down"))}" +
|
||||
"${getKeycapPC(ControlPresets.getKey("control_key_up"))}${getKeycapPC(ControlPresets.getKey("control_key_down"))}" +
|
||||
" ${Lang["MENU_CONTROLS_SCROLL"]}"
|
||||
else
|
||||
"${getKeycapConsole('R')} ${Lang["MENU_CONTROLS_SCROLL"]}"
|
||||
@@ -235,7 +235,7 @@ class UILoadList(val full: UILoadSavegame) : UICanvas() {
|
||||
if (showSpinner) {
|
||||
val spin = spinner.get(spinnerFrame % 8, spinnerFrame / 8)
|
||||
val offX = UIRemoCon.menubarOffX - UIRemoCon.UIRemoConElement.paddingLeft + 72 + 1
|
||||
val offY = UIRemoCon.menubarOffY - UIRemoCon.UIRemoConElement.lineHeight * 3 + 16
|
||||
val offY = UIRemoCon.menubarOffY - UIRemoCon.UIRemoConElement.lineHeight * 4 + 16
|
||||
batch.draw(spin, offX.toFloat(), offY.toFloat())
|
||||
}
|
||||
}
|
||||
@@ -249,12 +249,12 @@ class UILoadList(val full: UILoadSavegame) : UICanvas() {
|
||||
if (this.isVisible) {
|
||||
val cells = playerCells
|
||||
|
||||
if ((keycode == Input.Keys.UP || keycode == App.getConfigInt("control_key_up")) && scrollTarget > 0) {
|
||||
if ((keycode == Input.Keys.UP || keycode == ControlPresets.getKey("control_key_up")) && scrollTarget > 0) {
|
||||
scrollFrom = listScroll
|
||||
scrollTarget -= 1
|
||||
scrollAnimCounter = 0f
|
||||
}
|
||||
else if ((keycode == Input.Keys.DOWN || keycode == App.getConfigInt("control_key_down")) && scrollTarget < cells.size - savesVisible) {
|
||||
else if ((keycode == Input.Keys.DOWN || keycode == ControlPresets.getKey("control_key_down")) && scrollTarget < cells.size - savesVisible) {
|
||||
scrollFrom = listScroll
|
||||
scrollTarget += 1
|
||||
scrollAnimCounter = 0f
|
||||
|
||||
@@ -227,8 +227,8 @@ class UILoadManage(val full: UILoadSavegame) : UICanvas() {
|
||||
|
||||
}
|
||||
MODE_DELETE -> {
|
||||
Toolkit.drawTextCentered(batch, App.fontGame, Lang["MENU_LABEL_SAVE_WILL_BE_DELETED"], Toolkit.drawWidth, 0, full.titleTopGradEnd + full.cellInterval - 46)
|
||||
Toolkit.drawTextCentered(batch, App.fontGame, Lang["MENU_LABEL_ARE_YOU_SURE"], Toolkit.drawWidth, 0, full.titleTopGradEnd + full.cellInterval + SAVE_CELL_HEIGHT + 36)
|
||||
Toolkit.drawTextCentered(batch, App.fontGame, Lang["MENU_LABEL_SAVE_WILL_BE_DELETED"], Toolkit.drawWidth, 0, full.titleTopGradEnd + full.cellInterval + SAVE_CELL_HEIGHT + 36)
|
||||
Toolkit.drawTextCentered(batch, App.fontGame, Lang["MENU_LABEL_ARE_YOU_SURE"], Toolkit.drawWidth, 0, full.titleTopGradEnd + full.cellInterval + SAVE_CELL_HEIGHT + 36 + 24)
|
||||
|
||||
delButtons.forEach { it.render(batch, camera) }
|
||||
}
|
||||
|
||||
@@ -90,8 +90,17 @@ class UILoadSavegame(val remoCon: UIRemoCon) : Advanceable() {
|
||||
listOf(NullUI/*, transitionalAutosave*/)
|
||||
)
|
||||
|
||||
internal fun queueUpManageScr() { transitionPanel.setCentreUIto(0) }
|
||||
internal fun queueUpNewCharScr() { transitionPanel.setCentreUIto(1) }
|
||||
private val nodesForListing = Yaml(UITitleRemoConYaml.injectedMenuSingleCharSel).parse()
|
||||
private val nodesForManage = Yaml(UITitleRemoConYaml.injectedMenuSingleSaveManage).parse()
|
||||
|
||||
internal fun queueUpManageScr() {
|
||||
transitionPanel.setCentreUIto(0)
|
||||
remoCon.setNewRemoConContents(nodesForManage)
|
||||
}
|
||||
internal fun queueUpNewCharScr() {
|
||||
transitionPanel.setCentreUIto(1)
|
||||
remoCon.setNewRemoConContents(nodesForListing)
|
||||
}
|
||||
|
||||
// internal fun bringAutosaveSelectorUp() { transitionPanel.setRightUIto(1) }
|
||||
// internal fun takeAutosaveSelectorDown() { transitionPanel.setRightUIto(0) }
|
||||
@@ -102,6 +111,10 @@ class UILoadSavegame(val remoCon: UIRemoCon) : Advanceable() {
|
||||
|
||||
internal fun changePanelTo(index: Int) {
|
||||
transitionPanel.requestTransition(index)
|
||||
if (index == 1)
|
||||
remoCon.setNewRemoConContents(nodesForManage)
|
||||
else
|
||||
remoCon.setNewRemoConContents(nodesForListing)
|
||||
}
|
||||
|
||||
override fun advanceMode(button: UIItem) {
|
||||
@@ -118,6 +131,9 @@ class UILoadSavegame(val remoCon: UIRemoCon) : Advanceable() {
|
||||
// takeAutosaveSelectorDown()
|
||||
transitionPanel.show()
|
||||
|
||||
nodesForListing.parent = remoCon.treeRoot
|
||||
nodesForManage.parent = remoCon.treeRoot
|
||||
|
||||
}
|
||||
|
||||
override fun hide() {
|
||||
|
||||
@@ -26,11 +26,14 @@ class UIPerformanceControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
||||
arrayOf("", { Lang["MENU_OPTIONS_GAMEPLAY"] }, "h1"),
|
||||
arrayOf("autosaveinterval", { Lang["MENU_OPTIONS_AUTOSAVE"] + " (${Lang["CONTEXT_TIME_MINUTE_PLURAL"]})" }, "spinnerimul,1,120,1,60000"),
|
||||
arrayOf("notificationshowuptime", { Lang["MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION"] + " (${Lang["CONTEXT_TIME_SECOND_PLURAL"]})" }, "spinnerimul,2,10,1,1000"),
|
||||
arrayOf("", { Lang["MENU_LABEL_GRAPHICS"] }, "h1"),
|
||||
arrayOf("atlastexsize", { Lang["MENU_OPTIONS_ATLAS_TEXTURE_SIZE"] }, "spinnersel,1024,2048,4096,8192"),
|
||||
arrayOf("", { Lang["MENU_LABEL_JVM_DNT"] }, "h1"),
|
||||
arrayOf("jvm_xmx", { Lang["MENU_OPTIONS_JVM_HEAP_MAX"] + " (GB)" }, "spinner,2,32,1"),
|
||||
arrayOf("jvm_extra_cmd", { Lang["MENU_LABEL_EXTRA_JVM_ARGUMENTS"] }, "typein"),
|
||||
arrayOf("", { "(${Lang["MENU_LABEL_RESTART_REQUIRED"]})" }, "p"),
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override var height = ControlPanelCommon.getMenuHeight("basegame.performancecontrolpanel")
|
||||
|
||||
@@ -18,6 +18,11 @@ import kotlin.math.roundToInt
|
||||
* Created by minjaesong on 2016-07-20.
|
||||
*/
|
||||
class UIQuickslotBar : UICanvas() {
|
||||
|
||||
init {
|
||||
handler.allowESCtoClose = false
|
||||
}
|
||||
|
||||
private val cellSize = ItemSlotImageFactory.slotImage.tileW // 38
|
||||
|
||||
private val gutter = 10 - 6 // do -6 to get a gutter size of not-enlarged cells
|
||||
|
||||
@@ -21,6 +21,11 @@ import kotlin.math.roundToInt
|
||||
* Created by minjaesong on 2016-07-20.
|
||||
*/
|
||||
class UIQuickslotPie : UICanvas() {
|
||||
|
||||
init {
|
||||
handler.allowESCtoClose = false
|
||||
}
|
||||
|
||||
private val cellSize = ItemSlotImageFactory.slotImage.tileW
|
||||
|
||||
private val slotCount = UIQuickslotBar.SLOT_COUNT
|
||||
|
||||
@@ -18,10 +18,14 @@ import kotlin.math.roundToInt
|
||||
* Created by minjaesong on 2019-08-11.
|
||||
*/
|
||||
class UIScreenZoom : UICanvas(
|
||||
App.getConfigInt("control_key_zoom")
|
||||
"control_key_zoom"
|
||||
) {
|
||||
|
||||
val zoomText = "${getKeycapPC(handler.toggleKeyLiteral!!)} $EMDASH Zoom Out"
|
||||
init {
|
||||
handler.allowESCtoClose = false
|
||||
}
|
||||
|
||||
val zoomText = "${getKeycapPC(handler.toggleKey!!)} $EMDASH Zoom Out"
|
||||
|
||||
override var width = App.fontGame.getWidth(zoomText)
|
||||
override var height = App.fontGame.lineHeight.toInt()
|
||||
|
||||
@@ -19,8 +19,8 @@ import kotlin.math.min
|
||||
* Created by minjaesong on 2019-07-08.
|
||||
*/
|
||||
internal class UIStorageChest : UICanvas(
|
||||
toggleKeyLiteral = App.getConfigInt("control_key_inventory"),
|
||||
toggleButtonLiteral = App.getConfigInt("control_gamepad_start"),
|
||||
toggleKeyLiteral = "control_key_inventory",
|
||||
toggleButtonLiteral = "control_gamepad_start",
|
||||
), HasInventory {
|
||||
|
||||
lateinit var chestInventory: FixtureInventory
|
||||
@@ -175,7 +175,7 @@ internal class UIStorageChest : UICanvas(
|
||||
|
||||
private val controlHelp: String
|
||||
get() = if (App.environment == RunningEnvironment.PC)
|
||||
"${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||
"${getKeycapPC(ControlPresets.getKey("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||
else
|
||||
"${App.gamepadLabelStart} ${Lang["GAME_ACTION_CLOSE"]} "
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ class UITierOneWatch() : UICanvas() {
|
||||
ELuptimer += delta
|
||||
}
|
||||
|
||||
if (mouseUp || Gdx.input.isKeyPressed(App.getConfigInt("control_key_interact"))) {
|
||||
if (mouseUp || Gdx.input.isKeyPressed(ControlPresets.getKey("control_key_interact"))) {
|
||||
ELuptimer = 0f
|
||||
ELon = true
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ class UITitleModules(val remoCon: UIRemoCon) : UICanvas() {
|
||||
|
||||
private val controlHelp: String
|
||||
get() = if (App.environment == RunningEnvironment.PC)
|
||||
"${getKeycapPC(App.getConfigInt("control_key_up"))}${getKeycapPC(App.getConfigInt("control_key_down"))}" +
|
||||
"${getKeycapPC(ControlPresets.getKey("control_key_up"))}${getKeycapPC(ControlPresets.getKey("control_key_down"))}" +
|
||||
" ${Lang["MENU_CONTROLS_SCROLL"]}"
|
||||
else
|
||||
"${getKeycapConsole('R')} ${Lang["MENU_CONTROLS_SCROLL"]}"
|
||||
@@ -206,12 +206,12 @@ class UITitleModules(val remoCon: UIRemoCon) : UICanvas() {
|
||||
|
||||
override fun keyDown(keycode: Int): Boolean {
|
||||
if (this.isVisible) {
|
||||
if ((keycode == Input.Keys.UP || keycode == App.getConfigInt("control_key_up")) && scrollTarget > 0) {
|
||||
if ((keycode == Input.Keys.UP || keycode == ControlPresets.getKey("control_key_up")) && scrollTarget > 0) {
|
||||
scrollFrom = listScroll
|
||||
scrollTarget -= 1
|
||||
scrollAnimCounter = 0f
|
||||
}
|
||||
else if ((keycode == Input.Keys.DOWN || keycode == App.getConfigInt("control_key_down")) && scrollTarget < moduleCells.size - savesVisible) {
|
||||
else if ((keycode == Input.Keys.DOWN || keycode == ControlPresets.getKey("control_key_down")) && scrollTarget < moduleCells.size - savesVisible) {
|
||||
scrollFrom = listScroll
|
||||
scrollTarget += 1
|
||||
scrollAnimCounter = 0f
|
||||
|
||||
@@ -41,6 +41,7 @@ object UITitleRemoConYaml {
|
||||
|
||||
// todo add MENU_IO_IMPORT
|
||||
val injectedMenuSingleCharSel = """
|
||||
- MENU_IO_IMPORT : net.torvald.terrarum.modulebasegame.ui.UIImportAvatar
|
||||
- CONTEXT_CHARACTER_NEW : net.torvald.terrarum.modulebasegame.ui.UINewCharacter
|
||||
- MENU_LABEL_RETURN
|
||||
"""
|
||||
@@ -48,6 +49,12 @@ object UITitleRemoConYaml {
|
||||
val injectedMenuSingleWorldSel = """
|
||||
- CONTEXT_WORLD_NEW : net.torvald.terrarum.modulebasegame.ui.UINewWorld
|
||||
- MENU_LABEL_RETURN
|
||||
"""
|
||||
|
||||
val injectedMenuSingleSaveManage = """
|
||||
- MENU_MODULES
|
||||
- MENU_LABEL_PREV_SAVES
|
||||
- MENU_LABEL_RETURN
|
||||
"""
|
||||
|
||||
operator fun invoke(hasSave: Boolean) =
|
||||
|
||||
@@ -14,6 +14,10 @@ import net.torvald.terrarum.ui.UICanvas
|
||||
*/
|
||||
class UITooltip : UICanvas() {
|
||||
|
||||
init {
|
||||
handler.allowESCtoClose = false
|
||||
}
|
||||
|
||||
override var openCloseTime: Second = 0f
|
||||
|
||||
private val tooltipBackCol = Color.WHITE
|
||||
|
||||
@@ -21,6 +21,10 @@ class UIVitalMetre(
|
||||
val order: Int
|
||||
) : UICanvas() {
|
||||
|
||||
init {
|
||||
handler.allowESCtoClose = false
|
||||
}
|
||||
|
||||
init {
|
||||
// semitransparent
|
||||
color?.a = 0.91f
|
||||
|
||||
382
src/net/torvald/terrarum/modulebasegame/ui/UIWallCalendar.kt
Normal file
382
src/net/torvald/terrarum/modulebasegame/ui/UIWallCalendar.kt
Normal file
@@ -0,0 +1,382 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.gameworld.WorldTime
|
||||
import net.torvald.terrarum.gameworld.WorldTime.Companion.MONTH_LENGTH
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.unicode.getKeycapPC
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-08-15.
|
||||
*/
|
||||
class UIWallCalendar : UICanvas(
|
||||
toggleKeyLiteral = "control_key_inventory",
|
||||
toggleButtonLiteral = "control_gamepad_start",
|
||||
) {
|
||||
private val yearCellWidth = 200
|
||||
private val cellWidth = 80
|
||||
private val cellHeight = 24
|
||||
|
||||
override var width: Int = Toolkit.drawWidth
|
||||
override var height: Int = App.scr.height
|
||||
|
||||
private val y = UIInventoryFull.INVENTORY_CELLS_OFFSET_Y() + 1 - 34
|
||||
|
||||
private val drawStartX = (Toolkit.drawWidth - cellWidth * 8) / 2 - 4
|
||||
private val cellsStartY = y + 34
|
||||
|
||||
private val SP = "\u3000 "
|
||||
val controlHelp: String
|
||||
get() = if (App.environment == RunningEnvironment.PC)
|
||||
"${getKeycapPC(ControlPresets.getKey("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||
else
|
||||
"${App.gamepadLabelStart} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||
|
||||
|
||||
private var todayCell = -1
|
||||
|
||||
private val cellBackCols = listOf(
|
||||
Color(0x3f1e22_C8), // OKLCh 14, 5, 18
|
||||
Color(0x022f3a_C8), // OKLCh 218, 5, 18
|
||||
Color(0x2d2b09_C8), // OKLCh 105, 5, 18
|
||||
Color(0x252934_C8) // OKLCh 265, 2, 18
|
||||
)
|
||||
private val seasonMarkers = listOf(
|
||||
7 to "CONTEXT_CALENDAR_SEASON_SPRING",
|
||||
39 to "CONTEXT_CALENDAR_SEASON_SUMMER",
|
||||
71 to "CONTEXT_CALENDAR_SEASON_AUTUMN",
|
||||
103 to "CONTEXT_CALENDAR_SEASON_WINTER"
|
||||
)
|
||||
|
||||
private var mouseOverCell = -1
|
||||
private var mouseOverSeason = -1
|
||||
|
||||
override fun updateUI(delta: Float) {
|
||||
mouseOverCell = if (relativeMouseX in drawStartX until drawStartX + 8 * (cellWidth + 1) &&
|
||||
relativeMouseY in cellsStartY - 1 until cellsStartY - 1 + 17 * (cellHeight + 3)) {
|
||||
|
||||
val x = (relativeMouseX - drawStartX) / (cellWidth + 1)
|
||||
val y = (relativeMouseY - cellsStartY + 1) / (cellHeight + 3)
|
||||
|
||||
// disable highlighting on invalid date (verddag and not winter 30)
|
||||
if (x == 7 && y < 16) -1
|
||||
else y * 8 + x
|
||||
}
|
||||
else -1
|
||||
|
||||
mouseOverSeason = when (mouseOverCell) {
|
||||
-1 -> -1
|
||||
in 0 until 34 -> 0
|
||||
in 34 until 68 -> 1
|
||||
in 68 until 102 -> 2
|
||||
else -> 3
|
||||
}
|
||||
}
|
||||
|
||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||
UIInventoryFull.drawBackground(batch, 1f)
|
||||
|
||||
val thisYear = INGAME.world.worldTime.years
|
||||
val today = INGAME.world.worldTime.ordinalDay + 1
|
||||
val todayOfWeek = INGAME.world.worldTime.dayOfWeek
|
||||
|
||||
// cell background
|
||||
batch.color = Toolkit.Theme.COL_CELL_FILL
|
||||
Toolkit.fillArea(batch, (width - yearCellWidth) / 2, y - 34, yearCellWidth, 24)
|
||||
for (week in 0..7) {
|
||||
Toolkit.fillArea(batch, drawStartX + (cellWidth + 1) * week + 1, y, cellWidth - 2, 24)
|
||||
}
|
||||
for (cellNum in 0 until 17 * 8) {
|
||||
batch.color = when (cellNum) {
|
||||
in 0 until 34 -> cellBackCols[0]
|
||||
in 34 until 68 -> cellBackCols[1]
|
||||
in 68 until 102 -> cellBackCols[2]
|
||||
else -> cellBackCols[3]
|
||||
}
|
||||
if (cellNum % 8 != 7 || cellNum == 17 * 8 - 1) {
|
||||
Toolkit.fillArea(batch, drawStartX + (cellWidth + 1) * (cellNum % 8) + 1, cellsStartY + (cellHeight + 3) * (cellNum / 8), cellWidth - 2, cellHeight)
|
||||
}
|
||||
}
|
||||
// season name cell background
|
||||
for (k in 0..3) {
|
||||
batch.color = cellBackCols[k]
|
||||
Toolkit.fillArea(batch, drawStartX + (cellWidth + 1) * 7 + 1, cellsStartY + (cellHeight + 3) * (k * 4), cellWidth - 2, (cellHeight + 3) * 4 - 3)
|
||||
}
|
||||
|
||||
|
||||
// cell border
|
||||
batch.color = Toolkit.Theme.COL_INACTIVE
|
||||
Toolkit.drawBoxBorder(batch, (width - yearCellWidth) / 2 - 1, y - 35, yearCellWidth + 2, 26)
|
||||
Toolkit.drawBoxBorder(batch, drawStartX, y - 1, 8 * (cellWidth + 1) - 1, 26)
|
||||
for (week in 0..7) {
|
||||
Toolkit.drawBoxBorder(batch, drawStartX + (cellWidth + 1) * week, y - 1, cellWidth, 26)
|
||||
}
|
||||
// highlight a day name of mouse-up
|
||||
batch.color = Toolkit.Theme.COL_MOUSE_UP
|
||||
if (mouseOverCell >= 0) Toolkit.drawBoxBorder(batch, drawStartX + (cellWidth + 1) * (mouseOverCell % 8), y - 1, cellWidth, 26)
|
||||
// highlight today's week name
|
||||
batch.color = Toolkit.Theme.COL_SELECTED
|
||||
Toolkit.drawBoxBorder(batch, drawStartX + (cellWidth + 1) * todayOfWeek, y - 1, cellWidth, 26)
|
||||
|
||||
|
||||
// draw days grid
|
||||
batch.color = Toolkit.Theme.COL_INACTIVE
|
||||
Toolkit.drawBoxBorder(batch, drawStartX, cellsStartY - 1, 8 * (cellWidth + 1) - 1, 17 * (cellHeight + 3) - 1)
|
||||
// non-season-name-cells
|
||||
for (cellNum in 0 until 17 * 8) {
|
||||
if (cellNum % 8 != 7 || cellNum == 17 * 8 - 1) {
|
||||
Toolkit.drawBoxBorder(batch, drawStartX + (cellWidth + 1) * (cellNum % 8), cellsStartY + (cellHeight + 3) * (cellNum / 8) - 1, cellWidth, cellHeight + 2)
|
||||
}
|
||||
}
|
||||
// season-name-cells
|
||||
for (k in 0..3) {
|
||||
Toolkit.drawBoxBorder(batch, drawStartX + (cellWidth + 1) * 7, cellsStartY + (cellHeight + 3) * (k * 4) - 1, cellWidth, (cellHeight + 3) * 4 - 1)
|
||||
}
|
||||
// highlight a day of mouse-up
|
||||
batch.color = Toolkit.Theme.COL_MOUSE_UP
|
||||
if (mouseOverCell >= 0) Toolkit.drawBoxBorder(batch, drawStartX + (cellWidth + 1) * (mouseOverCell % 8), cellsStartY + (cellHeight + 3) * (mouseOverCell / 8) - 1, cellWidth, cellHeight + 2)
|
||||
|
||||
|
||||
// season border
|
||||
batch.color = Toolkit.Theme.COL_MOUSE_UP
|
||||
if (mouseOverSeason == 0) {
|
||||
Toolkit.drawStraightLine(batch,
|
||||
drawStartX,
|
||||
cellsStartY - 2,
|
||||
drawStartX + (cellWidth + 1) * 8 - 1,
|
||||
1,
|
||||
false
|
||||
)
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX - 1,
|
||||
cellsStartY - 1,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 5 - 3,
|
||||
1,
|
||||
true
|
||||
)
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX + (cellWidth + 1) * 8 - 1,
|
||||
cellsStartY - 1,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 4 - 3,
|
||||
1,
|
||||
true
|
||||
)
|
||||
}
|
||||
if (mouseOverSeason in 0..1) {
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 5 - 3,
|
||||
drawStartX + (cellWidth + 1) * 2 - 1,
|
||||
1,
|
||||
false
|
||||
)
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX + (cellWidth + 1) * 2 - 1,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 4 - 2,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 5 - 3,
|
||||
1,
|
||||
true
|
||||
)
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX + (cellWidth + 1) * 2,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 4 - 3,
|
||||
drawStartX + (cellWidth + 1) * 8 - 1,
|
||||
1,
|
||||
false
|
||||
)
|
||||
}
|
||||
if (mouseOverSeason == 1) {
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX - 1,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 5 - 2,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 9 - 3,
|
||||
1,
|
||||
true
|
||||
)
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX + (cellWidth + 1) * 8 - 1,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 4 - 2,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 8 - 3,
|
||||
1,
|
||||
true
|
||||
)
|
||||
}
|
||||
if (mouseOverSeason in 1..2) {
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 9 - 3,
|
||||
drawStartX + (cellWidth + 1) * 4 - 1,
|
||||
1,
|
||||
false
|
||||
)
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX + (cellWidth + 1) * 4 - 1,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 8 - 2,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 9 - 3,
|
||||
1,
|
||||
true
|
||||
)
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX + (cellWidth + 1) * 4,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 8 - 3,
|
||||
drawStartX + (cellWidth + 1) * 8 - 1,
|
||||
1,
|
||||
false
|
||||
)
|
||||
}
|
||||
if (mouseOverSeason == 2) {
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX - 1,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 9 - 2,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 13 - 3,
|
||||
1,
|
||||
true
|
||||
)
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX + (cellWidth + 1) * 8 - 1,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 8 - 2,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 12 - 3,
|
||||
1,
|
||||
true
|
||||
)
|
||||
}
|
||||
if (mouseOverSeason in 2..3) {
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 13 - 3,
|
||||
drawStartX + (cellWidth + 1) * 6 - 1,
|
||||
1,
|
||||
false
|
||||
)
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX + (cellWidth + 1) * 6 - 1,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 12 - 2,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 13 - 3,
|
||||
1,
|
||||
true
|
||||
)
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX + (cellWidth + 1) * 6,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 12 - 3,
|
||||
drawStartX + (cellWidth + 1) * 8 - 1,
|
||||
1,
|
||||
false
|
||||
)
|
||||
}
|
||||
if (mouseOverSeason == 3) {
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX - 1,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 13 - 2,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 17 - 3,
|
||||
1,
|
||||
true
|
||||
)
|
||||
Toolkit.drawStraightLine(
|
||||
batch,
|
||||
drawStartX + (cellWidth + 1) * 8 - 1,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 12 - 2,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 17 - 3,
|
||||
1,
|
||||
true
|
||||
)
|
||||
Toolkit.drawStraightLine(batch,
|
||||
drawStartX,
|
||||
cellsStartY + 1 + (cellHeight + 3) * 17 - 3,
|
||||
drawStartX + (cellWidth + 1) * 8 - 1,
|
||||
1,
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
// cell texts
|
||||
batch.color = Toolkit.Theme.COL_LIST_DEFAULT
|
||||
Toolkit.drawTextCentered(batch, App.fontGame, Lang.getAndUseTemplate("CONTEXT_CALENDAR_DATE_FORMAT_Y", false, thisYear), yearCellWidth, (width - yearCellWidth) / 2, y - 34)
|
||||
for (week in 0..7) {
|
||||
// highlight this week and the mouse-up
|
||||
batch.color = if (week == todayOfWeek) Toolkit.Theme.COL_SELECTED else if (week == mouseOverCell % 8) Toolkit.Theme.COL_MOUSE_UP else Toolkit.Theme.COL_LIST_DEFAULT
|
||||
|
||||
val t = WorldTime.getDayName(week)
|
||||
val tlen = App.fontGame.getWidth(t)
|
||||
App.fontGame.draw(batch, t, drawStartX + (cellWidth + 1) * week + (cellWidth - tlen) / 2, y)
|
||||
}
|
||||
var dayAkku = 1
|
||||
for (cellNum in 0 until 17 * 8) {
|
||||
val day = if (cellNum == 17*8-1) 120 else if (cellNum % 8 == 7) 0 else dayAkku
|
||||
|
||||
if (day > 0) {
|
||||
// highlight today and the mouse-up
|
||||
batch.color = if (day == today) Toolkit.Theme.COL_SELECTED else if (cellNum == mouseOverCell) Toolkit.Theme.COL_MOUSE_UP else Toolkit.Theme.COL_LIST_DEFAULT
|
||||
|
||||
val t = "${(day % MONTH_LENGTH).let { if (it == 0) MONTH_LENGTH else it }}".padStart(2, '\u2007')
|
||||
App.fontGame.draw(batch, t, drawStartX + (cellWidth + 1) * (cellNum % 8) - 20 + cellWidth - 4, cellsStartY + (cellHeight + 3) * (cellNum / 8))
|
||||
|
||||
if (day == today) todayCell = cellNum
|
||||
|
||||
dayAkku += 1
|
||||
}
|
||||
}
|
||||
// draw seasonal names
|
||||
seasonMarkers.forEachIndexed { index, (cellNum, key) ->
|
||||
batch.color = if (index == mouseOverSeason) Toolkit.Theme.COL_MOUSE_UP else Toolkit.Theme.COL_INACTIVE
|
||||
Toolkit.drawTextCentered(batch, App.fontGame, Lang[key], cellWidth, drawStartX + (cellWidth + 1) * (cellNum % 8), cellsStartY + (cellHeight + 3) * (cellNum / 8) + ((cellHeight + 3) * 1.5f).floorToInt())
|
||||
}
|
||||
|
||||
// highlight today cell
|
||||
if (todayCell >= 0) {
|
||||
batch.color = Toolkit.Theme.COL_SELECTED
|
||||
Toolkit.drawBoxBorder(batch, drawStartX + (cellWidth + 1) * (todayCell % 8), cellsStartY + (cellHeight + 3) * (todayCell / 8) - 1, cellWidth, cellHeight + 2)
|
||||
}
|
||||
|
||||
// control hints
|
||||
batch.color = Color.WHITE
|
||||
App.fontGame.draw(batch, controlHelp, drawStartX + 2, cellsStartY+ 17 * (cellHeight + 3) + 6)
|
||||
}
|
||||
|
||||
override fun doOpening(delta: Float) {
|
||||
super.doOpening(delta)
|
||||
INGAME.pause()
|
||||
INGAME.setTooltipMessage(null)
|
||||
}
|
||||
|
||||
override fun doClosing(delta: Float) {
|
||||
super.doClosing(delta)
|
||||
INGAME.resume()
|
||||
INGAME.setTooltipMessage(null)
|
||||
}
|
||||
|
||||
override fun endOpening(delta: Float) {
|
||||
super.endOpening(delta)
|
||||
UIItemInventoryItemGrid.tooltipShowing.clear()
|
||||
INGAME.setTooltipMessage(null) // required!
|
||||
}
|
||||
|
||||
override fun endClosing(delta: Float) {
|
||||
super.endClosing(delta)
|
||||
UIItemInventoryItemGrid.tooltipShowing.clear()
|
||||
INGAME.setTooltipMessage(null) // required!
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.*
|
||||
@@ -31,8 +30,8 @@ import java.util.UUID
|
||||
* Created by minjaesong on 2023-05-19.
|
||||
*/
|
||||
class UIWorldPortal : UICanvas(
|
||||
toggleKeyLiteral = App.getConfigInt("control_key_inventory"),
|
||||
toggleButtonLiteral = App.getConfigInt("control_gamepad_start"),
|
||||
toggleKeyLiteral = "control_key_inventory",
|
||||
toggleButtonLiteral = "control_gamepad_start",
|
||||
) {
|
||||
|
||||
override var width: Int = Toolkit.drawWidth
|
||||
@@ -54,7 +53,7 @@ class UIWorldPortal : UICanvas(
|
||||
private val SP = "\u3000 "
|
||||
val portalListingControlHelp: String
|
||||
get() = if (App.environment == RunningEnvironment.PC)
|
||||
"${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||
"${getKeycapPC(ControlPresets.getKey("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||
else
|
||||
"${App.gamepadLabelStart} ${Lang["GAME_ACTION_CLOSE"]}" +
|
||||
"$SP${App.gamepadLabelLT} ${Lang["GAME_WORLD_SEARCH"]}" +
|
||||
|
||||
@@ -167,7 +167,7 @@ class UIWorldPortalCargo(val full: UIWorldPortal) : UICanvas(), HasInventory {
|
||||
|
||||
private val controlHelp: String
|
||||
get() = if (App.environment == RunningEnvironment.PC)
|
||||
"${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||
"${getKeycapPC(ControlPresets.getKey("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||
else
|
||||
"${App.gamepadLabelStart} ${Lang["GAME_ACTION_CLOSE"]} "
|
||||
|
||||
|
||||
@@ -4,27 +4,26 @@ import net.torvald.terrarum.savegame.toBigEndian
|
||||
import java.util.UUID
|
||||
import kotlin.math.ceil
|
||||
|
||||
/**
|
||||
* Ascii85 implementation with my own character table based on RFC 1924. Will NOT truncate '00000' into something else;
|
||||
* just gzip the inputstream instead!
|
||||
/** My own string set that:
|
||||
* - no "/": avoids nonstandard JSON comment key which GDX will happily parse away
|
||||
* - no "\": you know what I mean\\intention
|
||||
* - no "$": avoids Kotlin string template
|
||||
* - no "[{]},": even the dumbest parser can comprehend the output
|
||||
*/
|
||||
object Ascii85 {
|
||||
/** My own string set that:
|
||||
* - no "/": avoids nonstandard JSON comment key which GDX will happily parse away
|
||||
* - no "\": you know what I mean\\intention
|
||||
* - no "$": avoids Kotlin string template
|
||||
* - no "[{]},": even the dumbest parser can comprehend the output
|
||||
*/
|
||||
private const val CHAR_TABLE = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#%&'()*+-.:;<=>?@^_`|~"
|
||||
open class Ascii85Codec(private val CHAR_TABLE: String = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#%&'()*+-.:;<=>?@^_`|~") {
|
||||
init {
|
||||
if (CHAR_TABLE.length != 85) throw IllegalArgumentException("CHAR_TABLE is not 85 chars long")
|
||||
}
|
||||
|
||||
/** As per Adobe standard */
|
||||
//private val CHAR_TABLE = (33 until (33+85)).toList().map { it.toChar() }.joinToString("") // testing only!
|
||||
|
||||
private val INVERSE_TABLE = LongArray(127)
|
||||
|
||||
/** Int of `-1` */
|
||||
const val PAD_BYTE = -1
|
||||
val PAD_BYTE = -1
|
||||
/** Null-character (`\0`) */
|
||||
const val PAD_CHAR = 0.toChar()
|
||||
val PAD_CHAR = 0.toChar()
|
||||
|
||||
private val INTERNAL_PAD_BYTE = 0
|
||||
private val INTERNAL_PAD_CHAR = CHAR_TABLE.last()
|
||||
@@ -97,10 +96,10 @@ object Ascii85 {
|
||||
}
|
||||
|
||||
val sum = (INVERSE_TABLE[s1.toInt()] * 52200625) +
|
||||
(INVERSE_TABLE[s2.toInt()] * 614125) +
|
||||
(INVERSE_TABLE[s3.toInt()] * 7225) +
|
||||
(INVERSE_TABLE[s4.toInt()] * 85) +
|
||||
INVERSE_TABLE[s5.toInt()]
|
||||
(INVERSE_TABLE[s2.toInt()] * 614125) +
|
||||
(INVERSE_TABLE[s3.toInt()] * 7225) +
|
||||
(INVERSE_TABLE[s4.toInt()] * 85) +
|
||||
INVERSE_TABLE[s5.toInt()]
|
||||
return ByteArray(4 - padLen) { sum.ushr((3 - it) * 8).and(255).toByte() }
|
||||
}
|
||||
|
||||
@@ -137,6 +136,12 @@ object Ascii85 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ascii85 implementation with my own character table based on RFC 1924. Will NOT truncate '00000' into something else;
|
||||
* just gzip the inputstream instead!
|
||||
*/
|
||||
object Ascii85 : Ascii85Codec()
|
||||
|
||||
fun UUID.toAscii85() =
|
||||
Ascii85.encodeBytes(this.mostSignificantBits.toBigEndian() + this.leastSignificantBits.toBigEndian())
|
||||
fun String.ascii85toUUID(): UUID {
|
||||
|
||||
@@ -165,7 +165,7 @@ class BasicDebugInfoWindow : UICanvas() {
|
||||
App.fontSmallNumbers.draw(batch, "${if (player.jumping) "$ccG" else "$ccK"}JM", gap + 7f*(jX + 8), line(jY))
|
||||
App.fontSmallNumbers.draw(batch, "${if (player.isJumpDown) "$ccG" else "$ccK"}KY", gap + 7f*(jX + 8), line(jY+1))
|
||||
|
||||
App.fontSmallNumbers.draw(batch, "${if (player.downDownVirtually) "$ccG" else "$ccK"}$ARROW_DOWN", gap + 7f*(jX + 11), line(jY+1))
|
||||
App.fontSmallNumbers.draw(batch, "${if (player.downButtonHeld > 0) "$ccG" else "$ccK"}$ARROW_DOWN", gap + 7f*(jX + 11), line(jY+1))
|
||||
|
||||
App.fontSmallNumbers.draw(batch, "$WIDTH$ccG${player.hitbox.width.toString().padEnd(5).substring(0,5).trim()}$ccY$HEIGHT$ccG${player.hitbox.height.toString().padEnd(5).substring(0,5)}", gap + 7f*(jX + 13), line(jY))
|
||||
App.fontSmallNumbers.draw(batch, "$MASS$ccG${player.mass.toString().padEnd(8).substring(0,8)}", gap + 7f*(jX + 13), line(jY+1))
|
||||
@@ -199,7 +199,7 @@ class BasicDebugInfoWindow : UICanvas() {
|
||||
val soldeg = WeatherMixer.forceSolarElev ?: world?.worldTime?.solarElevationDeg
|
||||
val soldegStr = (soldeg ?: 0.0).toIntAndFrac(3,2)
|
||||
val soldegNeg = ((soldeg ?: 0.0) >= 0.0).toInt()
|
||||
val turbidity = WeatherMixer.forceTurbidity ?: WeatherMixer.turbidity
|
||||
val turbidity = (WeatherMixer.forceTurbidity ?: WeatherMixer.turbidity).toIntAndFrac(1, 4)
|
||||
|
||||
val soldegCol = if (WeatherMixer.forceSolarElev != null) ccO else ccG
|
||||
val turbCol = if (WeatherMixer.forceTurbidity != null) ccO else ccG
|
||||
@@ -292,15 +292,17 @@ class BasicDebugInfoWindow : UICanvas() {
|
||||
|
||||
if (ingame != null) {
|
||||
App.fontSmallNumbers.draw(batch, "${ccY}Actors total $ccG${ingame!!.actorContainerActive.size + ingame!!.actorContainerInactive.size}",
|
||||
TinyAlphNum.W * 2f, App.scr.height - TinyAlphNum.H * 2f)
|
||||
TinyAlphNum.W * 2f, App.scr.height - TinyAlphNum.H * 2f)
|
||||
App.fontSmallNumbers.draw(batch, "${ccY}Active $ccG${ingame!!.actorContainerActive.size}",
|
||||
(TinyAlphNum.W * 2 + 17 * 8).toFloat(), App.scr.height - TinyAlphNum.H * 2f)
|
||||
TinyAlphNum.W * 2f + (17 * 8), App.scr.height - TinyAlphNum.H * 2f)
|
||||
App.fontSmallNumbers.draw(batch, "${ccY}Dormant $ccG${ingame!!.actorContainerInactive.size}",
|
||||
(TinyAlphNum.W * 2 + 28 * 8).toFloat(), App.scr.height - TinyAlphNum.H * 2f)
|
||||
TinyAlphNum.W * 2f + (28 * 8), App.scr.height - TinyAlphNum.H * 2f)
|
||||
if (ingame is TerrarumIngame) {
|
||||
App.fontSmallNumbers.draw(batch, "${ccM}Particles $ccG${(ingame as TerrarumIngame).particlesActive}",
|
||||
(TinyAlphNum.W * 2 + 41 * 8).toFloat(), App.scr.height - TinyAlphNum.H * 2f)
|
||||
App.fontSmallNumbers.draw(batch, "${ccM}Particles $ccG${(ingame as TerrarumIngame).particlesActive}$ccY/$ccG${(ingame as TerrarumIngame).PARTICLES_MAX}",
|
||||
TinyAlphNum.W * 2f, App.scr.height - TinyAlphNum.H * 4f)
|
||||
}
|
||||
App.fontSmallNumbers.draw(batch, "${ccM}Clouds $ccG${WeatherMixer.cloudsSpawned}$ccY/$ccG${WeatherMixer.cloudSpawnMax}",
|
||||
TinyAlphNum.W * 2f + (18 * 8), App.scr.height - TinyAlphNum.H * 4f)
|
||||
}
|
||||
|
||||
App.fontSmallNumbers.draw(batch, "${ccY}Actors rendering $ccG${IngameRenderer.renderingActorsCount}",
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import com.badlogic.gdx.graphics.glutils.FloatFrameBuffer
|
||||
import com.badlogic.gdx.graphics.glutils.Float16FrameBuffer
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.random.HQRNG
|
||||
@@ -48,9 +48,9 @@ object Toolkit : Disposable {
|
||||
private val shaderBoxDown = App.loadShaderFromClasspath("shaders/default.vert", "shaders/boxdown.frag")
|
||||
private val shaderBoxUp = App.loadShaderFromClasspath("shaders/default.vert", "shaders/boxup.frag")
|
||||
|
||||
private lateinit var fboBlur: FloatFrameBuffer
|
||||
private lateinit var fboBlurHalf: FloatFrameBuffer
|
||||
private lateinit var fboBlurQuarter: FloatFrameBuffer
|
||||
private lateinit var fboBlur: Float16FrameBuffer
|
||||
private lateinit var fboBlurHalf: Float16FrameBuffer
|
||||
private lateinit var fboBlurQuarter: Float16FrameBuffer
|
||||
private lateinit var blurWriteQuad: Mesh
|
||||
private lateinit var blurWriteQuad2: Mesh
|
||||
private lateinit var blurWriteQuad4: Mesh
|
||||
@@ -326,17 +326,17 @@ object Toolkit : Disposable {
|
||||
val fw = App.scr.width//MathUtils.nextPowerOfTwo(App.scr.width)
|
||||
val fh = App.scr.height//MathUtils.nextPowerOfTwo(App.scr.height)
|
||||
|
||||
fboBlur = FloatFrameBuffer(
|
||||
fboBlur = Float16FrameBuffer(
|
||||
fw,
|
||||
fh,
|
||||
false
|
||||
)
|
||||
fboBlurHalf = FloatFrameBuffer(
|
||||
fboBlurHalf = Float16FrameBuffer(
|
||||
fw / 2,
|
||||
fh / 2,
|
||||
false
|
||||
)
|
||||
fboBlurQuarter = FloatFrameBuffer(
|
||||
fboBlurQuarter = Float16FrameBuffer(
|
||||
fw / 4,
|
||||
fh / 4,
|
||||
false
|
||||
|
||||
@@ -59,7 +59,7 @@ import kotlin.math.roundToInt
|
||||
* Created by minjaesong on 2015-12-31.
|
||||
*/
|
||||
abstract class UICanvas(
|
||||
toggleKeyLiteral: Int? = null, toggleButtonLiteral: Int? = null,
|
||||
toggleKeyLiteral: String? = null, toggleButtonLiteral: String? = null,
|
||||
// UI positions itself? (you must g.flush() yourself after the g.translate(Int, Int))
|
||||
customPositioning: Boolean = false, // mainly used by vital meter
|
||||
doNotWarnConstant: Boolean = false
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.ControlPresets
|
||||
import net.torvald.terrarum.FlippingSpriteBatch
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gamecontroller.KeyToggler
|
||||
@@ -25,12 +26,12 @@ import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
* Created by minjaesong on 2015-12-31.
|
||||
*/
|
||||
class UIHandler(//var UI: UICanvas,
|
||||
var toggleKeyLiteral: Int? = null,
|
||||
var toggleButtonLiteral: Int? = null,
|
||||
var toggleKeyLiteral: String? = null, // string key of the config
|
||||
var toggleButtonLiteral: String? = null, // string key of the config
|
||||
// UI positions itself? (you must g.flush() yourself after the g.translate(Int, Int))
|
||||
var customPositioning: Boolean = false, // mainly used by vital meter
|
||||
var doNotWarnConstant: Boolean = false,
|
||||
internal var allowESCtoClose: Boolean = false,
|
||||
internal var allowESCtoClose: Boolean = true,
|
||||
var uiTogglerFunctionDefault: ((UIHandler) -> Unit)? = null
|
||||
): Disposable {
|
||||
|
||||
@@ -130,12 +131,13 @@ void main() {
|
||||
//UI.handler = this
|
||||
}
|
||||
|
||||
|
||||
private val toggleKey: Int?; get() = toggleKeyLiteral // to support in-screen keybind changing
|
||||
private val toggleButton: Int?; get() = toggleButtonLiteral // to support in-screen keybind changing
|
||||
// ControlPresets.getKey(toggleKeyLiteral)
|
||||
val toggleKey: Int?; get() = ControlPresets.getKey(toggleKeyLiteral).let { if (it == -1) null else it } // to support in-screen keybind changing
|
||||
// ControlPresets.getKey(toggleButtonLiteral)
|
||||
val toggleButton: Int?; get() = ControlPresets.getKey(toggleButtonLiteral).let { if (it == -1) null else it } // to support in-screen keybind changing
|
||||
|
||||
|
||||
val toggleKeyExtra: ArrayList<() -> Int> = arrayListOf()
|
||||
val toggleKeyExtra: ArrayList<String> = arrayListOf()
|
||||
|
||||
/**
|
||||
* Takes a function that works with UIHandler.
|
||||
@@ -207,14 +209,14 @@ void main() {
|
||||
else uiTogglerFunctionDefault!!.invoke(this)
|
||||
}
|
||||
|
||||
toggleKeyExtra.forEachIndexed { index, getKey ->
|
||||
if (Gdx.input.isKeyJustPressed(getKey())) {
|
||||
toggleKeyExtra.forEachIndexed { index, control ->
|
||||
if (Gdx.input.isKeyJustPressed(ControlPresets.getKey(control))) {
|
||||
toggleKeyExtraAction[index].invoke(this)
|
||||
}
|
||||
}
|
||||
|
||||
// ESC is a master key for closing
|
||||
if (allowESCtoClose && Gdx.input.isKeyJustPressed(Input.Keys.ESCAPE) && isOpened) {
|
||||
if (!alwaysVisible && allowESCtoClose && Gdx.input.isKeyJustPressed(Input.Keys.ESCAPE) && isOpened) {
|
||||
setAsClose()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,15 +17,15 @@ import kotlin.math.roundToInt
|
||||
*/
|
||||
|
||||
class UIItemSpinner(
|
||||
parentUI: UICanvas,
|
||||
initialX: Int, initialY: Int,
|
||||
private var initialValue: Number,
|
||||
val min: Number,
|
||||
val max: Number,
|
||||
val step: Number,
|
||||
override val width: Int,
|
||||
private val drawBorder: Boolean = true,
|
||||
private val numberToTextFunction: (Number) -> String = { "$it" }
|
||||
parentUI: UICanvas,
|
||||
initialX: Int, initialY: Int,
|
||||
private var initialValue: Number,
|
||||
val min: Number,
|
||||
val max: Number,
|
||||
val step: Number,
|
||||
override val width: Int,
|
||||
private val drawBorder: Boolean = true,
|
||||
private val numberToTextFunction: (Number) -> String = { "$it" }
|
||||
) : UIItem(parentUI, initialX, initialY) {
|
||||
|
||||
// to alleviate floating point errors adding up as the spinner is being used
|
||||
|
||||
@@ -443,7 +443,7 @@ class UIItemTextLineInput(
|
||||
|
||||
if (!mouseDown) mouseLatched = false
|
||||
|
||||
imeOn = KeyToggler.isOn(App.getConfigInt("control_key_toggleime"))
|
||||
imeOn = KeyToggler.isOn(ControlPresets.getKey("control_key_toggleime"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,7 +468,7 @@ class UIItemTextLineInput(
|
||||
endComposing()
|
||||
|
||||
imeOn = !imeOn
|
||||
KeyToggler.forceSet(App.getConfigInt("control_key_toggleime"), imeOn)
|
||||
KeyToggler.forceSet(ControlPresets.getKey("control_key_toggleime"), imeOn)
|
||||
}
|
||||
|
||||
private fun resetIME() {
|
||||
|
||||
@@ -17,13 +17,14 @@ import net.torvald.terrarum.gameworld.fmod
|
||||
* Created by minjaesong on 2021-10-21.
|
||||
*/
|
||||
class UIItemTextSelector(
|
||||
parentUI: UICanvas,
|
||||
initialX: Int, initialY: Int,
|
||||
val labelfuns: List<() -> String>,
|
||||
initialSelection: Int,
|
||||
override val width: Int,
|
||||
private val drawBorder: Boolean = true,
|
||||
private val clickToShowPalette: Boolean = true
|
||||
parentUI: UICanvas,
|
||||
initialX: Int, initialY: Int,
|
||||
val labelfuns: List<() -> String>,
|
||||
initialSelection: Int,
|
||||
override val width: Int,
|
||||
private val drawBorder: Boolean = true,
|
||||
private val clickToShowPalette: Boolean = true,
|
||||
private val useSpinnerButtons: Boolean = false,
|
||||
) : UIItem(parentUI, initialX, initialY) {
|
||||
|
||||
init {
|
||||
@@ -127,6 +128,9 @@ class UIItemTextSelector(
|
||||
else if (!Terrarum.mouseDown) mouseLatched = false
|
||||
}
|
||||
|
||||
private val leftIcon = if (useSpinnerButtons) labels.get(9,2) else labels.get(16,0)
|
||||
private val rightIcon = if (useSpinnerButtons) labels.get(10,2) else labels.get(17,0)
|
||||
|
||||
override fun render(batch: SpriteBatch, camera: Camera) {
|
||||
labelCache = labelfuns.map { it() }
|
||||
|
||||
@@ -184,12 +188,12 @@ class UIItemTextSelector(
|
||||
// left button icon
|
||||
batch.color = if (mouseOnButton == 1 && mousePushed) Toolkit.Theme.COL_SELECTED
|
||||
else if (mouseOnButton == 1) Toolkit.Theme.COL_MOUSE_UP else UIItemTextLineInput.TEXTINPUT_COL_TEXT
|
||||
batch.draw(labels.get(16,0), posX + (buttonW - labels.tileW) / 2f, posY + (height - labels.tileH) / 2f)
|
||||
batch.draw(leftIcon, posX + (buttonW - labels.tileW) / 2f, posY + (height - labels.tileH) / 2f)
|
||||
|
||||
// right button icon
|
||||
batch.color = if (mouseOnButton == 2 && mousePushed) Toolkit.Theme.COL_SELECTED
|
||||
else if (mouseOnButton == 2) Toolkit.Theme.COL_MOUSE_UP else UIItemTextLineInput.TEXTINPUT_COL_TEXT
|
||||
batch.draw(labels.get(17,0), posX + width - buttonW + (buttonW - labels.tileW) / 2f, posY + (height - labels.tileH) / 2f)
|
||||
batch.draw(rightIcon, posX + width - buttonW + (buttonW - labels.tileW) / 2f, posY + (height - labels.tileH) / 2f)
|
||||
|
||||
// draw text
|
||||
if (!paletteShowing) {
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
package net.torvald.terrarum.weather
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.math.Vector2
|
||||
import com.badlogic.gdx.math.Vector3
|
||||
import com.badlogic.gdx.utils.JsonValue
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.GdxColorMap
|
||||
import java.util.*
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
/**
|
||||
* Note: Colour maps are likely to have sparse data points
|
||||
@@ -12,10 +17,49 @@ import java.util.*
|
||||
* Created by minjaesong on 2016-07-11.
|
||||
*/
|
||||
data class BaseModularWeather(
|
||||
var skyboxGradColourMap: GdxColorMap, // row 0: skybox grad top, row 1: skybox grad bottom, row 2: sunlight (RGBA)
|
||||
val daylightClut: GdxColorMap,
|
||||
val classification: String,
|
||||
var extraImages: ArrayList<Texture>,
|
||||
val mixFrom: String? = null,
|
||||
val mixPercentage: Double? = null
|
||||
)
|
||||
val json: JsonValue,
|
||||
var skyboxGradColourMap: GdxColorMap, // row 0: skybox grad top, row 1: skybox grad bottom, row 2: sunlight (RGBA)
|
||||
val daylightClut: GdxColorMap,
|
||||
val classification: String,
|
||||
val cloudChance: Float,
|
||||
val windSpeed: Float,
|
||||
val windSpeedVariance: Float,
|
||||
val cloudGamma: Vector2,
|
||||
val cloudGammaVariance: Vector2,
|
||||
var clouds: List<CloudProps>, // sorted by CloudProps.probability
|
||||
|
||||
val mixFrom: String? = null,
|
||||
val mixPercentage: Double? = null,
|
||||
|
||||
var forceWindVec: Vector3? = null
|
||||
) {
|
||||
/**
|
||||
* @param rnd random number between -1 and +1
|
||||
*/
|
||||
fun getRandomWindSpeed(rnd: Float): Float {
|
||||
val v = 1f + rnd.absoluteValue * windSpeedVariance
|
||||
return if (rnd < 0) windSpeed / v else windSpeed * v
|
||||
}
|
||||
}
|
||||
|
||||
data class CloudProps(
|
||||
val category: String,
|
||||
val spriteSheet: TextureRegionPack,
|
||||
val probability: Float,
|
||||
val baseScale: Float,
|
||||
val scaleVariance: Float,
|
||||
val altLow: Float,
|
||||
val altHigh: Float,
|
||||
) {
|
||||
init {
|
||||
spriteSheet.texture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rnd random number between -1 and +1
|
||||
*/
|
||||
fun getCloudScaleVariance(rnd: Float): Float {
|
||||
val v = 1f + rnd.absoluteValue * scaleVariance
|
||||
return if (rnd < 0) baseScale / v else baseScale * v
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,11 @@ package net.torvald.terrarum.weather
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import com.badlogic.gdx.math.Vector2
|
||||
import com.badlogic.gdx.math.Vector3
|
||||
import com.badlogic.gdx.utils.JsonValue
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.random.HQRNG
|
||||
@@ -16,9 +20,18 @@ import net.torvald.terrarum.gameworld.WorldTime.Companion.DAY_LENGTH
|
||||
import net.torvald.terrarum.RNGConsumer
|
||||
import net.torvald.terrarum.clut.Skybox
|
||||
import net.torvald.terrarum.utils.JsonFetcher
|
||||
import net.torvald.terrarum.utils.forEachSiblings
|
||||
import net.torvald.terrarum.weather.WeatherObjectCloud.Companion.ALPHA_ROLLOFF_Z
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import net.torvald.util.SortedArrayList
|
||||
import java.io.File
|
||||
import java.io.FileFilter
|
||||
import java.lang.Double.doubleToLongBits
|
||||
import java.lang.Math.toDegrees
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.math.*
|
||||
|
||||
/**
|
||||
* Currently there is a debate whether this module must be part of the engine or the basegame
|
||||
@@ -50,10 +63,11 @@ internal object WeatherMixer : RNGConsumer {
|
||||
lateinit var mixedWeather: BaseModularWeather
|
||||
|
||||
val globalLightNow = Cvec(0)
|
||||
private val moonlightMax = Cvec(0.23f, 0.24f, 0.25f, 0.21f) // actual moonlight is around ~4100K but our mesopic vision makes it appear blueish (wikipedia: Purkinje effect)
|
||||
|
||||
// Weather indices
|
||||
const val WEATHER_GENERIC = "generic"
|
||||
const val WEATHER_GENERIC_RAIN = "genericrain"
|
||||
const val WEATHER_OVERCAST = "overcast"
|
||||
// TODO add weather classification indices manually
|
||||
|
||||
// TODO to save from GL overhead, store lightmap to array; use GdxColorMap
|
||||
@@ -68,16 +82,23 @@ internal object WeatherMixer : RNGConsumer {
|
||||
it.texture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat)
|
||||
}
|
||||
|
||||
private val shaderBlendMax = App.loadShaderFromClasspath("shaders/blendSkyboxStars.vert", "shaders/blendSkyboxStars.frag")
|
||||
private val shaderAstrum = App.loadShaderFromClasspath("shaders/blendSkyboxStars.vert", "shaders/blendSkyboxStars.frag")
|
||||
private val shaderClouds = App.loadShaderFromClasspath("shaders/default.vert", "shaders/clouds.frag")
|
||||
|
||||
private var astrumOffX = 0f
|
||||
private var astrumOffY = 0f
|
||||
|
||||
private val moonlightMax = Cvec(0.23f, 0.24f, 0.25f, 0.21f) // actual moonlight is around ~4100K but our mesopic vision makes it appear blueish (wikipedia: Purkinje effect)
|
||||
private val clouds = SortedArrayList<WeatherObjectCloud>()
|
||||
var cloudsSpawned = 0; private set
|
||||
private var windVector = Vector3(-1f, 0f, 0.1f) // this is a direction vector
|
||||
val cloudSpawnMax: Int
|
||||
get() = 256 shl (App.getConfigInt("maxparticles") / 256)
|
||||
|
||||
override fun loadFromSave(s0: Long, s1: Long) {
|
||||
super.loadFromSave(s0, s1)
|
||||
currentWeather = weatherList[WEATHER_GENERIC]!![0]
|
||||
internalReset(s0, s1)
|
||||
initClouds()
|
||||
}
|
||||
|
||||
fun internalReset() = internalReset(RNG.state0, RNG.state1)
|
||||
@@ -90,6 +111,15 @@ internal object WeatherMixer : RNGConsumer {
|
||||
|
||||
astrumOffX = s0.and(0xFFFFL).toFloat() / 65535f * starmapTex.regionWidth
|
||||
astrumOffY = s1.and(0xFFFFL).toFloat() / 65535f * starmapTex.regionHeight
|
||||
|
||||
clouds.clear()
|
||||
cloudsSpawned = 0
|
||||
windVector = Vector3(-0.98f, 0f, 0.21f)
|
||||
|
||||
windDirWindow = null
|
||||
windSpeedWindow = null
|
||||
|
||||
oldCamPos.set(WorldCamera.camVector)
|
||||
}
|
||||
|
||||
init {
|
||||
@@ -121,6 +151,7 @@ internal object WeatherMixer : RNGConsumer {
|
||||
|
||||
// initialise
|
||||
try {
|
||||
weatherList["titlescreen"] = arrayListOf(weatherList[WEATHER_GENERIC]!![0].copy(windSpeed = 1f))
|
||||
currentWeather = weatherList[WEATHER_GENERIC]!![0]
|
||||
nextWeather = getRandomWeather(WEATHER_GENERIC)
|
||||
}
|
||||
@@ -128,10 +159,16 @@ internal object WeatherMixer : RNGConsumer {
|
||||
e.printStackTrace()
|
||||
|
||||
val defaultWeather = BaseModularWeather(
|
||||
JsonValue(JsonValue.ValueType.`object`),
|
||||
GdxColorMap(1, 3, Color(0x55aaffff), Color(0xaaffffff.toInt()), Color.WHITE),
|
||||
GdxColorMap(2, 2, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE),
|
||||
"default",
|
||||
ArrayList<Texture>()
|
||||
0f,
|
||||
0f,
|
||||
0f,
|
||||
Vector2(1f, 1f),
|
||||
Vector2(0f, 0f),
|
||||
listOf()
|
||||
)
|
||||
|
||||
currentWeather = defaultWeather
|
||||
@@ -147,6 +184,9 @@ internal object WeatherMixer : RNGConsumer {
|
||||
|
||||
// currentWeather = weatherList[WEATHER_GENERIC]!![0] // force set weather
|
||||
|
||||
updateWind(delta, world)
|
||||
updateClouds(delta, world)
|
||||
|
||||
|
||||
if (!globalLightOverridden) {
|
||||
world.globalLight = WeatherMixer.globalLightNow
|
||||
@@ -154,8 +194,330 @@ internal object WeatherMixer : RNGConsumer {
|
||||
|
||||
}
|
||||
|
||||
var turbidity = 4.0; private set
|
||||
private var gH = 1.4f * App.scr.height
|
||||
private fun FloatArray.shiftAndPut(f: Float) {
|
||||
for (k in 1 until this.size) {
|
||||
this[k-1] = this[k]
|
||||
}
|
||||
this[this.lastIndex] = f
|
||||
}
|
||||
|
||||
private val PI = 3.1415927f
|
||||
private val TWO_PI = 6.2831855f
|
||||
private val THREE_PI = 9.424778f
|
||||
|
||||
private var windDirWindow: FloatArray? = null
|
||||
private var windSpeedWindow: FloatArray? = null
|
||||
private val WIND_DIR_TIME_UNIT = 14400 // every 4hr
|
||||
private val WIND_SPEED_TIME_UNIT = 3600 // every 1hr
|
||||
private var windDirAkku = 0 // only needed if timeDelta is not divisible by WIND_TIME_UNIT
|
||||
private var windSpeedAkku = 0
|
||||
|
||||
// see: https://stackoverflow.com/questions/2708476/rotation-interpolation/14498790#14498790
|
||||
private fun getShortestAngle(start: Float, end: Float) =
|
||||
(((((end - if (start < 0f) TWO_PI + start else start) % TWO_PI) + THREE_PI) % TWO_PI) - PI).let {
|
||||
if (it > PI) it - TWO_PI else it
|
||||
}
|
||||
|
||||
private fun updateWind(delta: Float, world: GameWorld) {
|
||||
if (windDirWindow == null) {
|
||||
windDirWindow = FloatArray(4) { takeUniformRand(-PI..PI) } // completely random regardless of the seed
|
||||
}
|
||||
if (windSpeedWindow == null) {
|
||||
windSpeedWindow = FloatArray(4) { currentWeather.getRandomWindSpeed(takeTriangularRand(-1f..1f)) } // completely random regardless of the seed
|
||||
}
|
||||
|
||||
val windDirStep = windDirAkku / WIND_DIR_TIME_UNIT.toFloat()
|
||||
val windSpeedStep = windSpeedAkku / WIND_SPEED_TIME_UNIT.toFloat()
|
||||
|
||||
// val angle0 = windDirWindow[0]
|
||||
// val angle1 = getShortestAngle(angle0, windDirWindow[1])
|
||||
// val angle2 = getShortestAngle(angle1, windDirWindow[2])
|
||||
// val angle3 = getShortestAngle(angle2, windDirWindow[3])
|
||||
// val fixedAngles = floatArrayOf(angle0, angle1, angle2, angle3)
|
||||
|
||||
val currentWindDir = FastMath.interpolateCatmullRom(windDirStep, windDirWindow)
|
||||
val currentWindSpeed = FastMath.interpolateCatmullRom(windSpeedStep, windSpeedWindow)
|
||||
/*
|
||||
printdbg(this,
|
||||
"dir ${Math.toDegrees(currentWindDir.toDouble()).roundToInt()}\t" +
|
||||
"spd ${currentWindSpeed.times(10f).roundToInt().div(10f)}\t " +
|
||||
"dirs ${windDirWindow!!.map { Math.toDegrees(it.toDouble()).roundToInt() }} ${windDirStep.times(100).roundToInt()}\t" +
|
||||
"spds ${windSpeedWindow!!.map { it.times(10f).roundToInt().div(10f) }} ${windSpeedStep.times(100).roundToInt()}"
|
||||
)*/
|
||||
|
||||
if (currentWeather.forceWindVec != null) {
|
||||
windVector.set(currentWeather.forceWindVec)
|
||||
}
|
||||
else {
|
||||
windVector.set(
|
||||
cos(currentWindDir) * currentWindSpeed,
|
||||
0f,
|
||||
sin(currentWindDir) * currentWindSpeed
|
||||
)
|
||||
}
|
||||
|
||||
while (windDirAkku >= WIND_DIR_TIME_UNIT) {
|
||||
windDirAkku -= WIND_DIR_TIME_UNIT
|
||||
windDirWindow!!.shiftAndPut(takeUniformRand(-PI..PI))
|
||||
}
|
||||
while (windSpeedAkku >= WIND_SPEED_TIME_UNIT) {
|
||||
windSpeedAkku -= WIND_SPEED_TIME_UNIT
|
||||
windSpeedWindow!!.shiftAndPut(currentWeather.getRandomWindSpeed(takeTriangularRand(-1f..1f)))
|
||||
}
|
||||
|
||||
windDirAkku += world.worldTime.timeDelta
|
||||
windSpeedAkku += world.worldTime.timeDelta
|
||||
}
|
||||
|
||||
private val cloudParallaxMultY = -0.035f
|
||||
private val cloudParallaxMultX = -0.035f
|
||||
private var cloudUpdateAkku = 0f
|
||||
private val oldCamPos = Vector2(0f, 0f)
|
||||
private val camDelta = Vector2(0f, 0f)
|
||||
|
||||
val oobMarginR = 1.5f * App.scr.wf
|
||||
val oobMarginL = -0.5f * App.scr.wf
|
||||
private val oobMarginY = -0.5f * App.scr.hf
|
||||
|
||||
private val DEBUG_CAUSE_OF_DESPAWN = false
|
||||
|
||||
private fun updateClouds(delta: Float, world: GameWorld) {
|
||||
val camvec = WorldCamera.camVector
|
||||
val camvec2 = camvec.cpy()
|
||||
val testCamDelta = camvec.cpy().sub(oldCamPos)
|
||||
|
||||
if (testCamDelta.x.absoluteValue > world.width * TILE_SIZEF / 2f) {
|
||||
if (testCamDelta.x >= 0)
|
||||
camvec2.x -= world.width * TILE_SIZEF
|
||||
else
|
||||
camvec2.x += world.width * TILE_SIZEF
|
||||
|
||||
testCamDelta.set(camvec2.sub(oldCamPos))
|
||||
}
|
||||
|
||||
camDelta.set(testCamDelta)
|
||||
|
||||
|
||||
val cloudChanceEveryMin = 60f / (currentWeather.cloudChance * currentWeather.windSpeed) // if chance = 0, the result will be +inf
|
||||
|
||||
while (cloudUpdateAkku >= cloudChanceEveryMin) {
|
||||
cloudUpdateAkku -= cloudChanceEveryMin
|
||||
tryToSpawnCloud(currentWeather)
|
||||
}
|
||||
|
||||
|
||||
var immDespawnCount = 0
|
||||
val immDespawnCauses = ArrayList<String>()
|
||||
clouds.forEach {
|
||||
// do parallax scrolling
|
||||
it.posX += camDelta.x * cloudParallaxMultX
|
||||
it.posY += camDelta.y * cloudParallaxMultY
|
||||
|
||||
|
||||
it.update(windVector)
|
||||
|
||||
if (DEBUG_CAUSE_OF_DESPAWN && it.life == 0) {
|
||||
immDespawnCount += 1
|
||||
immDespawnCauses.add(it.despawnCode)
|
||||
}
|
||||
}
|
||||
|
||||
// printdbg(this, "Newborn cloud death rate: $immDespawnCount/$cloudsSpawned")
|
||||
|
||||
|
||||
if (DEBUG_CAUSE_OF_DESPAWN && App.IS_DEVELOPMENT_BUILD && immDespawnCount > cloudsSpawned / 4) {
|
||||
val despawnCauseStats = HashMap<String, Int>()
|
||||
immDespawnCauses.forEach {
|
||||
if (despawnCauseStats[it] != null) {
|
||||
despawnCauseStats[it] = despawnCauseStats[it]!! + 1
|
||||
}
|
||||
else {
|
||||
despawnCauseStats[it] = 1
|
||||
}
|
||||
}
|
||||
despawnCauseStats.forEach { s, i ->
|
||||
printdbg(this, "Cause of death -- $s: $i")
|
||||
}
|
||||
System.exit(0)
|
||||
}
|
||||
|
||||
|
||||
// remove clouds that are marked to be despawn
|
||||
var i = 0
|
||||
while (true) {
|
||||
if (i >= clouds.size) break
|
||||
|
||||
if (clouds[i].flagToDespawn) {
|
||||
clouds.removeAt(i)
|
||||
i -= 1
|
||||
cloudsSpawned -= 1
|
||||
}
|
||||
|
||||
i += 1
|
||||
}
|
||||
|
||||
|
||||
cloudUpdateAkku += delta
|
||||
|
||||
|
||||
oldCamPos.set(camvec)
|
||||
}
|
||||
|
||||
private val scrHscaler = App.scr.height / 720f
|
||||
private val cloudSizeMult = App.scr.wf / TerrarumScreenSize.defaultW
|
||||
|
||||
private fun takeUniformRand(range: ClosedFloatingPointRange<Float>) =
|
||||
FastMath.interpolateLinear(Math.random().toFloat(), range.start, range.endInclusive)
|
||||
private fun takeTriangularRand(range: ClosedFloatingPointRange<Float>) =
|
||||
FastMath.interpolateLinear((Math.random() + Math.random()).div(2f).toFloat(), range.start, range.endInclusive)
|
||||
private fun takeGaussianRand(range: ClosedFloatingPointRange<Float>) =
|
||||
FastMath.interpolateLinear((Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random()).div(8f).toFloat(), range.start, range.endInclusive)
|
||||
|
||||
/**
|
||||
* Returns random point for clouds to spawn from, in the opposite side of the current wind vector
|
||||
*/
|
||||
private fun getCloudSpawningPosition(cloud: CloudProps, halfCloudSize: Float, windVector: Vector3): Vector3 {
|
||||
val Z_LIM = ALPHA_ROLLOFF_Z/2f
|
||||
val y = takeUniformRand(-cloud.altHigh..-cloud.altLow) * scrHscaler
|
||||
|
||||
var windVectorDir = toDegrees(atan2(windVector.z.toDouble(), windVector.x.toDouble())).toFloat() + 180f
|
||||
if (windVectorDir < 0f) windVectorDir += 360f
|
||||
windVectorDir /= 90f // full circle: 4
|
||||
|
||||
// an "edge" is a line of length 1 drawn into the edge of the square of size 1 (its total edge length will be 4)
|
||||
// when the windVectorDir is not an integer, the "edge" will take the shape similar to this: ¬
|
||||
// 'rr' is a point on the "edge", where 0.5 is a middle point in its length
|
||||
// val rl = (windVectorDir % 1f).let { if (it < 0.5f) -it else it - 1f }.toInt()
|
||||
// val rh = 1 + (windVectorDir % 1f).let { if (it < 0.5f) it else 1f - it }.toInt()
|
||||
|
||||
// choose between rl and rh using (windVectorDir % 1f) as a pivot
|
||||
// if pivot = 0.3, rL is 70%, and rR is 30% likely
|
||||
// plug the vote result into the when()
|
||||
val selectedQuadrant = takeUniformRand(windVectorDir..windVectorDir + 1f)
|
||||
|
||||
// printdbg(this, "Dir: $windVectorDir, Rand(${windVectorDir}..${windVectorDir + 1f}) = ${selectedQuadrant.floorToInt()}($selectedQuadrant)")
|
||||
|
||||
val rr = takeUniformRand(0f..1f)
|
||||
|
||||
return when (selectedQuadrant.floorToInt()) {
|
||||
-4, 0, 4 -> { // right side of the screen
|
||||
val z = FastMath.interpolateLinear(rr, 1f, ALPHA_ROLLOFF_Z).pow(1.5f) // clouds are more likely to spawn with low Z-value
|
||||
val posXscr = App.scr.width + halfCloudSize
|
||||
val x = WeatherObjectCloud.screenXtoWorldX(posXscr, z)
|
||||
Vector3(x, y, z)
|
||||
}
|
||||
-3, 1, 5 -> { // z = inf
|
||||
val z = ALPHA_ROLLOFF_Z
|
||||
val posXscr = FastMath.interpolateLinear(rr, App.scr.width + halfCloudSize, -halfCloudSize)
|
||||
val x = WeatherObjectCloud.screenXtoWorldX(posXscr, Z_LIM)
|
||||
Vector3(x, y, z)
|
||||
}
|
||||
-2, 2, 6 -> { // left side of the screen
|
||||
val z = FastMath.interpolateLinear(rr, ALPHA_ROLLOFF_Z, 1f).pow(1.5f) // clouds are more likely to spawn with low Z-value
|
||||
val posXscr = -halfCloudSize
|
||||
val x = WeatherObjectCloud.screenXtoWorldX(posXscr, z)
|
||||
Vector3(x, y, z)
|
||||
}
|
||||
-1, 3, 7 -> { // z = 0
|
||||
val z = 0.1f
|
||||
val posXscr = FastMath.interpolateLinear(rr, -halfCloudSize, App.scr.width + halfCloudSize)
|
||||
val x = WeatherObjectCloud.screenXtoWorldX(posXscr, Z_LIM)
|
||||
Vector3(x, y, z)
|
||||
}
|
||||
else -> throw InternalError()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun tryToSpawnCloud(currentWeather: BaseModularWeather, precalculatedPos: Vector3? = null) {
|
||||
// printdbg(this, "Trying to spawn a cloud... (${cloudsSpawned} / ${cloudSpawnMax})")
|
||||
|
||||
if (cloudsSpawned < cloudSpawnMax) {
|
||||
val flip = Math.random() < 0.5
|
||||
val rC = takeUniformRand(0f..1f)
|
||||
// val rZ = takeUniformRand(1f..ALPHA_ROLLOFF_Z/4f).pow(1.5f) // clouds are more likely to spawn with low Z-value
|
||||
// val rY = takeUniformRand(-1f..1f)
|
||||
val rT1 = takeTriangularRand(-1f..1f)
|
||||
val (rA, rB) = doubleToLongBits(Math.random()).let {
|
||||
it.ushr(20).and(0xFFFF).toInt() to it.ushr(36).and(0xFFFF).toInt()
|
||||
}
|
||||
|
||||
var cloudsToSpawn: CloudProps? = null
|
||||
var c = 0
|
||||
while (c < currentWeather.clouds.size) {
|
||||
if (rC < currentWeather.clouds[c].probability) {
|
||||
cloudsToSpawn = currentWeather.clouds[c]
|
||||
break
|
||||
}
|
||||
c += 1
|
||||
}
|
||||
|
||||
cloudsToSpawn?.let { cloud ->
|
||||
val cloudScale = cloud.getCloudScaleVariance(rT1)
|
||||
val hCloudSize = (cloud.spriteSheet.tileW * cloudScale) / 2f + 1f
|
||||
|
||||
// val posXscr = initX ?: if (cloudDriftVector.x < 0) (App.scr.width + hCloudSize) else -hCloudSize
|
||||
// val posX = WeatherObjectCloud.screenXtoWorldX(posXscr, rZ)
|
||||
// val posY = randomPosWithin(-cloud.altHigh..-cloud.altLow, rY) * scrHscaler
|
||||
|
||||
val sheetX = rA % cloud.spriteSheet.horizontalCount
|
||||
val sheetY = rB % cloud.spriteSheet.verticalCount
|
||||
WeatherObjectCloud(cloud.spriteSheet.get(sheetX, sheetY), flip).also {
|
||||
it.scale = cloudScale * cloudSizeMult
|
||||
|
||||
it.pos.set(precalculatedPos ?: getCloudSpawningPosition(cloud, hCloudSize, windVector))
|
||||
|
||||
// further set the random altitude if required
|
||||
if (precalculatedPos != null) {
|
||||
it.pos.y = takeUniformRand(-cloud.altHigh..-cloud.altLow) * scrHscaler
|
||||
}
|
||||
|
||||
clouds.add(it)
|
||||
cloudsSpawned += 1
|
||||
|
||||
|
||||
// printdbg(this, "... Spawning ${cloud.category}($sheetX, $sheetY) cloud at pos ${it.pos}, scale ${it.scale}, invGamma ${it.darkness}")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initClouds() {
|
||||
val hCloudSize = 1024f
|
||||
// multiplier is an empirical value that depends on the 'rZ'
|
||||
// it does converge at ~6, but having it as an initial state does not make it stay converged
|
||||
repeat((currentWeather.cloudChance * 1.333f).ceilToInt()) {
|
||||
|
||||
val z = takeUniformRand(0.1f..ALPHA_ROLLOFF_Z / 4f - 0.1f).pow(1.5f) // clouds are more likely to spawn with low Z-value
|
||||
|
||||
val zz = FastMath.interpolateLinear((z / ALPHA_ROLLOFF_Z) * 0.8f + 0.1f, ALPHA_ROLLOFF_Z / 4f, ALPHA_ROLLOFF_Z)
|
||||
|
||||
val x = WeatherObjectCloud.screenXtoWorldX(takeUniformRand(0f..App.scr.wf), zz)
|
||||
|
||||
|
||||
tryToSpawnCloud(currentWeather, Vector3(x, 0f, z))
|
||||
}
|
||||
}
|
||||
|
||||
internal fun titleScreenInitWeather() {
|
||||
currentWeather = weatherList["titlescreen"]!![0]
|
||||
currentWeather.forceWindVec = Vector3(-0.98f, 0f, -0.21f)
|
||||
initClouds()
|
||||
}
|
||||
|
||||
private fun <T> Array<T?>.addAtFreeSpot(obj: T) {
|
||||
var c = 0
|
||||
while (true) {
|
||||
if (this[c] == null) break
|
||||
c += 1
|
||||
}
|
||||
this[c] = obj
|
||||
}
|
||||
|
||||
|
||||
var turbidity = 1.0; private set
|
||||
private var gH = 1.8f * App.scr.height
|
||||
// private var gH = 0.8f * App.scr.height
|
||||
|
||||
internal var parallaxPos = 0f; private set
|
||||
@@ -166,11 +528,28 @@ internal object WeatherMixer : RNGConsumer {
|
||||
*/
|
||||
internal fun render(camera: Camera, batch: FlippingSpriteBatch, world: GameWorld) {
|
||||
drawSkybox(camera, batch, world)
|
||||
drawClouds(batch)
|
||||
batch.color = Color.WHITE
|
||||
}
|
||||
|
||||
private fun drawClouds(batch: SpriteBatch) {
|
||||
batch.inUse { _ ->
|
||||
batch.shader = shaderClouds
|
||||
batch.shader.setUniformf("gamma", currentWeather.cloudGamma)
|
||||
batch.shader.setUniformf("shadeCol", 0.06f, 0.07f, 0.08f, 1f) // TODO temporary value
|
||||
|
||||
clouds.forEach {
|
||||
batch.color = Color(globalLightNow.r, globalLightNow.g, globalLightNow.b, it.alpha)
|
||||
it.render(batch, 0f, 0f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val parallaxDomainSize = 400f
|
||||
private val turbidityDomainSize = 533.3333f
|
||||
|
||||
private fun drawSkybox(camera: Camera, batch: FlippingSpriteBatch, world: GameWorld) {
|
||||
val parallaxZeroPos = (world.height / 3f)
|
||||
val parallaxDomainSize = 300f
|
||||
|
||||
// we will not care for nextSkybox for now
|
||||
val timeNow = (forceTimeAt ?: world.worldTime.TIME_T.toInt()) % WorldTime.DAY_LENGTH
|
||||
@@ -199,17 +578,20 @@ internal object WeatherMixer : RNGConsumer {
|
||||
-+ <- 0.0 =
|
||||
*/
|
||||
val parallax = ((parallaxZeroPos - WorldCamera.gdxCamY.div(TILE_SIZEF)) / parallaxDomainSize).times(-1f).coerceIn(-1f, 1f)
|
||||
val turbidityCoeff = ((parallaxZeroPos - WorldCamera.gdxCamY.div(TILE_SIZEF)) / turbidityDomainSize).times(-1f).coerceIn(-1f, 1f)
|
||||
parallaxPos = parallax
|
||||
// println(parallax) // parallax value works as intended.
|
||||
|
||||
gdxBlendNormalStraightAlpha()
|
||||
|
||||
turbidity = (3.5 + turbidityCoeff * 2.5).coerceIn(1.0, 6.0)
|
||||
val thisTurbidity = forceTurbidity ?: turbidity
|
||||
|
||||
// TODO trilinear with (deg, turb, alb)
|
||||
val gradY = -(gH - App.scr.height) * ((parallax + 1f) / 2f)
|
||||
val (tex, uvs) = Skybox.getUV(solarElev, thisTurbidity, 0.3)
|
||||
|
||||
val (tex, uvs, turbX, albX) = Skybox.getUV(solarElev, thisTurbidity, 0.3)
|
||||
|
||||
val mornNoonBlend = (1f/4000f * (timeNow - 43200) + 0.5f).coerceIn(0f, 1f) // 0.0 at T41200; 0.5 at T43200; 1.0 at T45200;
|
||||
|
||||
starmapTex.texture.bind(1)
|
||||
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0) // so that batch that comes next will bind any tex to it
|
||||
@@ -218,22 +600,28 @@ internal object WeatherMixer : RNGConsumer {
|
||||
val astrumY = ((world.worldTime.TIME_T / WorldTime.DIURNAL_MOTION_LENGTH) % 1f) * starmapTex.regionHeight
|
||||
|
||||
batch.inUse {
|
||||
batch.shader = shaderBlendMax
|
||||
shaderBlendMax.setUniformi("tex1", 1)
|
||||
shaderBlendMax.setUniformf("drawOffset", 0f, gradY)
|
||||
shaderBlendMax.setUniformf("drawOffsetSize", App.scr.wf, gH)
|
||||
shaderBlendMax.setUniform2fv("skyboxUV1", uvs, 0, 2)
|
||||
shaderBlendMax.setUniform2fv("skyboxUV2", uvs, 2, 2)
|
||||
shaderBlendMax.setUniformf("astrumScroll", astrumOffX + astrumX, astrumOffY + astrumY)
|
||||
shaderBlendMax.setUniformf("randomNumber",
|
||||
batch.shader = shaderAstrum
|
||||
shaderAstrum.setUniformi("tex1", 1)
|
||||
shaderAstrum.setUniformf("drawOffsetSize", 0f, gradY, App.scr.wf, gH)
|
||||
shaderAstrum.setUniform4fv("uvA", uvs, 0, 4)
|
||||
shaderAstrum.setUniform4fv("uvB", uvs, 4, 4)
|
||||
shaderAstrum.setUniform4fv("uvC", uvs, 8, 4)
|
||||
shaderAstrum.setUniform4fv("uvD", uvs, 12, 4)
|
||||
shaderAstrum.setUniform4fv("uvE", uvs, 16, 4)
|
||||
shaderAstrum.setUniform4fv("uvF", uvs, 20, 4)
|
||||
shaderAstrum.setUniform4fv("uvG", uvs, 24, 4)
|
||||
shaderAstrum.setUniform4fv("uvH", uvs, 28, 4)
|
||||
shaderAstrum.setUniformf("texBlend", mornNoonBlend, turbX, albX, 0f)
|
||||
shaderAstrum.setUniformf("astrumScroll", astrumOffX + astrumX, astrumOffY + astrumY)
|
||||
shaderAstrum.setUniformf("randomNumber",
|
||||
// (world.worldTime.TIME_T.plus(31L) xor 1453L + 31L).and(1023).toFloat(),
|
||||
// (world.worldTime.TIME_T.plus(37L) xor 862L + 31L).and(1023).toFloat(),
|
||||
// (world.worldTime.TIME_T.plus(23L) xor 1639L + 29L).and(1023).toFloat(),
|
||||
// (world.worldTime.TIME_T.plus(29L) xor 2971L + 41L).and(1023).toFloat(),
|
||||
world.worldTime.TIME_T.div(+12.1f).plus(31L),
|
||||
world.worldTime.TIME_T.div(-11.8f).plus(37L),
|
||||
world.worldTime.TIME_T.div(+11.9f).plus(23L),
|
||||
world.worldTime.TIME_T.div(-12.3f).plus(29L),
|
||||
world.worldTime.TIME_T.div(+14.1f).plus(31L),
|
||||
world.worldTime.TIME_T.div(-13.8f).plus(37L),
|
||||
world.worldTime.TIME_T.div(+13.9f).plus(23L),
|
||||
world.worldTime.TIME_T.div(-14.3f).plus(29L),
|
||||
)
|
||||
|
||||
batch.color = Color.WHITE
|
||||
@@ -355,20 +743,36 @@ internal object WeatherMixer : RNGConsumer {
|
||||
|
||||
val skyboxInJson = JSON.getString("skyboxGradColourMap")
|
||||
val lightbox = JSON.getString("daylightClut")
|
||||
val extraImagesPath = JSON.get("extraImages").asStringArray()
|
||||
|
||||
val skybox = GdxColorMap(ModMgr.getGdxFile(modname, "$pathToImage/${skyboxInJson}"))
|
||||
val daylight = GdxColorMap(ModMgr.getGdxFile(modname, "$pathToImage/${lightbox}"))
|
||||
|
||||
|
||||
val extraImages = ArrayList<Texture>()
|
||||
for (i in extraImagesPath)
|
||||
extraImages.add(Texture(ModMgr.getGdxFile(modname, "$pathToImage/${i}")))
|
||||
|
||||
|
||||
val classification = JSON.getString("classification")
|
||||
|
||||
|
||||
val cloudsMap = ArrayList<CloudProps>()
|
||||
val clouds = JSON["clouds"]
|
||||
clouds.forEachSiblings { name, json ->
|
||||
cloudsMap.add(CloudProps(
|
||||
name,
|
||||
TextureRegionPack(ModMgr.getGdxFile(modname, "$pathToImage/${json.getString("filename")}"), json.getInt("tw"), json.getInt("th")),
|
||||
json.getFloat("probability"),
|
||||
json.getFloat("baseScale"),
|
||||
json.getFloat("scaleVariance"),
|
||||
json.getFloat("altLow"),
|
||||
json.getFloat("altHigh"),
|
||||
))
|
||||
}
|
||||
cloudsMap.sortBy { it.probability }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var mixFrom: String?
|
||||
try { mixFrom = JSON.getString("mixFrom") }
|
||||
@@ -383,20 +787,28 @@ internal object WeatherMixer : RNGConsumer {
|
||||
|
||||
|
||||
return BaseModularWeather(
|
||||
json = JSON,
|
||||
skyboxGradColourMap = skybox,
|
||||
daylightClut = daylight,
|
||||
classification = classification,
|
||||
extraImages = extraImages
|
||||
cloudChance = JSON.getFloat("cloudChance"),
|
||||
windSpeed = JSON.getFloat("windSpeed"),
|
||||
windSpeedVariance = JSON.getFloat("windSpeedVariance"),
|
||||
cloudGamma = JSON["cloudGamma"].asFloatArray().let { Vector2(it[0], it[1]) },
|
||||
cloudGammaVariance = JSON["cloudGammaVariance"].asFloatArray().let { Vector2(it[0], it[1]) },
|
||||
clouds = cloudsMap,
|
||||
)
|
||||
}
|
||||
|
||||
fun dispose() {
|
||||
weatherList.values.forEach { list ->
|
||||
list.forEach { weather ->
|
||||
weather.extraImages.forEach { it.tryDispose() }
|
||||
weather.clouds.forEach { it.spriteSheet.dispose() }
|
||||
}
|
||||
}
|
||||
starmapTex.texture.dispose()
|
||||
shaderBlendMax.dispose()
|
||||
shaderAstrum.dispose()
|
||||
shaderClouds.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user