mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-06 08:38:30 +09:00
Compare commits
30 Commits
v0.3.3-tes
...
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 |
@@ -5,10 +5,7 @@ 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.App
|
||||
import net.torvald.terrarum.FlippingSpriteBatch
|
||||
import net.torvald.terrarum.blendNormalStraightAlpha
|
||||
import net.torvald.terrarum.inAction
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulecomputers.gameactors.FixtureHomeComputer
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
@@ -18,8 +15,8 @@ import net.torvald.tsvm.peripheral.GraphicsAdapter
|
||||
import net.torvald.unicode.*
|
||||
|
||||
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"),
|
||||
toggleKeyLiteral = null,
|
||||
toggleButtonLiteral = "control_gamepad_start",
|
||||
) {
|
||||
override var width = 640
|
||||
override var height = 480
|
||||
@@ -45,7 +42,7 @@ internal class UIHomeComputer : UICanvas(
|
||||
private val fbo = FrameBuffer(Pixmap.Format.RGBA8888, width, height, false)
|
||||
|
||||
private val controlHelp =
|
||||
"${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}\u3000 " +
|
||||
"${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"
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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" : "재설정",
|
||||
|
||||
@@ -32,4 +32,5 @@ Teleport
|
||||
ToggleNoClip
|
||||
Zoom
|
||||
DynToStatic
|
||||
DebugFillInventory
|
||||
DebugFillInventory
|
||||
Uuid
|
||||
|
@@ -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": ""
|
||||
}
|
||||
@@ -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": ""
|
||||
}
|
||||
@@ -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.
@@ -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"
|
||||
|
||||
@@ -18,6 +18,9 @@ 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");
|
||||
}
|
||||
@@ -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) {}
|
||||
|
||||
|
||||
|
||||
@@ -269,8 +269,8 @@ public class App implements ApplicationListener {
|
||||
Gdx.gl20.glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
public static final int TICKS = 64;
|
||||
public static final float UPDATE_RATE = 1f / TICKS; // 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;
|
||||
@@ -1378,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) {
|
||||
|
||||
@@ -67,7 +67,7 @@ basegame
|
||||
// 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 = "test001"
|
||||
const val VERSION_TAG: String = "test002"
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// CONFIGURATION FOR TILE MAKER //
|
||||
|
||||
@@ -688,7 +688,7 @@ open class ActorWithBody : Actor {
|
||||
}
|
||||
|
||||
private fun displaceHitbox() {
|
||||
val printdbg1 = true && App.IS_DEVELOPMENT_BUILD
|
||||
val printdbg1 = false && App.IS_DEVELOPMENT_BUILD
|
||||
// // HOW IT SHOULD WORK // //
|
||||
// ////////////////////////
|
||||
// combineVeloToMoveDelta now
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -302,6 +302,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
|
||||
IngameRenderer.setRenderedWorld(gameWorld)
|
||||
WeatherMixer.internalReset()
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
|
||||
@@ -255,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
|
||||
|
||||
@@ -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
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
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() {
|
||||
}
|
||||
}
|
||||
@@ -254,11 +254,11 @@ open class ActorHumanoid : ActorWithBody, Controllable, Pocketed, Factionable, L
|
||||
|
||||
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
|
||||
|
||||
@@ -268,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"))
|
||||
}
|
||||
|
||||
@@ -348,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)) {
|
||||
@@ -376,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)) {
|
||||
|
||||
@@ -46,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
|
||||
}
|
||||
|
||||
@@ -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 " +
|
||||
|
||||
@@ -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
|
||||
@@ -162,10 +161,10 @@ class UIInventoryFull(
|
||||
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" +
|
||||
@@ -175,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" +
|
||||
@@ -183,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"]}"
|
||||
@@ -249,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)
|
||||
@@ -263,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"]}"
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
@@ -18,14 +18,14 @@ import kotlin.math.roundToInt
|
||||
* Created by minjaesong on 2019-08-11.
|
||||
*/
|
||||
class UIScreenZoom : UICanvas(
|
||||
App.getConfigInt("control_key_zoom")
|
||||
"control_key_zoom"
|
||||
) {
|
||||
|
||||
init {
|
||||
handler.allowESCtoClose = false
|
||||
}
|
||||
|
||||
val zoomText = "${getKeycapPC(handler.toggleKeyLiteral!!)} $EMDASH Zoom Out"
|
||||
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,7 +41,7 @@ object UITitleRemoConYaml {
|
||||
|
||||
// todo add MENU_IO_IMPORT
|
||||
val injectedMenuSingleCharSel = """
|
||||
- MENU_IO_IMPORT
|
||||
- MENU_IO_IMPORT : net.torvald.terrarum.modulebasegame.ui.UIImportAvatar
|
||||
- CONTEXT_CHARACTER_NEW : net.torvald.terrarum.modulebasegame.ui.UINewCharacter
|
||||
- MENU_LABEL_RETURN
|
||||
"""
|
||||
|
||||
@@ -3,10 +3,7 @@ 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.App
|
||||
import net.torvald.terrarum.INGAME
|
||||
import net.torvald.terrarum.RunningEnvironment
|
||||
import net.torvald.terrarum.floorToInt
|
||||
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
|
||||
@@ -18,8 +15,8 @@ import net.torvald.unicode.getKeycapPC
|
||||
* Created by minjaesong on 2023-08-15.
|
||||
*/
|
||||
class UIWallCalendar : UICanvas(
|
||||
toggleKeyLiteral = App.getConfigInt("control_key_inventory"),
|
||||
toggleButtonLiteral = App.getConfigInt("control_gamepad_start"),
|
||||
toggleKeyLiteral = "control_key_inventory",
|
||||
toggleButtonLiteral = "control_gamepad_start",
|
||||
) {
|
||||
private val yearCellWidth = 200
|
||||
private val cellWidth = 80
|
||||
@@ -36,7 +33,7 @@ class UIWallCalendar : UICanvas(
|
||||
private val SP = "\u3000 "
|
||||
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"]}"
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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}",
|
||||
|
||||
@@ -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,8 +26,8 @@ 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,
|
||||
@@ -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,8 +209,8 @@ 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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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,6 +194,328 @@ internal object WeatherMixer : RNGConsumer {
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
@@ -166,6 +528,21 @@ 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
|
||||
@@ -223,20 +600,20 @@ 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("drawOffsetSize", 0f, gradY, App.scr.wf, gH)
|
||||
shaderBlendMax.setUniform4fv("uvA", uvs, 0, 4)
|
||||
shaderBlendMax.setUniform4fv("uvB", uvs, 4, 4)
|
||||
shaderBlendMax.setUniform4fv("uvC", uvs, 8, 4)
|
||||
shaderBlendMax.setUniform4fv("uvD", uvs, 12, 4)
|
||||
shaderBlendMax.setUniform4fv("uvE", uvs, 16, 4)
|
||||
shaderBlendMax.setUniform4fv("uvF", uvs, 20, 4)
|
||||
shaderBlendMax.setUniform4fv("uvG", uvs, 24, 4)
|
||||
shaderBlendMax.setUniform4fv("uvH", uvs, 28, 4)
|
||||
shaderBlendMax.setUniformf("texBlend", mornNoonBlend, turbX, albX, 0f)
|
||||
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(),
|
||||
@@ -366,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") }
|
||||
@@ -394,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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
33
src/net/torvald/terrarum/weather/WeatherObject.kt
Normal file
33
src/net/torvald/terrarum/weather/WeatherObject.kt
Normal file
@@ -0,0 +1,33 @@
|
||||
package net.torvald.terrarum.weather
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.math.Vector3
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-08-21.
|
||||
*/
|
||||
abstract class WeatherObject : Disposable {
|
||||
|
||||
/** vec3(posX, posY, scale) */
|
||||
var pos: Vector3 = Vector3(0f, 0f, 1f)
|
||||
|
||||
var posX: Float
|
||||
get() = pos.x
|
||||
set(value) { pos.x = value }
|
||||
var posY: Float
|
||||
get() = pos.y
|
||||
set(value) { pos.y = value }
|
||||
var posZ: Float
|
||||
get() = pos.z
|
||||
set(value) { pos.z = value }
|
||||
var scale: Float = 1f
|
||||
|
||||
var alpha: Float = 1f
|
||||
|
||||
var flagToDespawn = false
|
||||
|
||||
abstract fun update()
|
||||
abstract fun render(batch: SpriteBatch, offsetX: Float, offsetY: Float)
|
||||
|
||||
}
|
||||
137
src/net/torvald/terrarum/weather/WeatherObjectCloud.kt
Normal file
137
src/net/torvald/terrarum/weather/WeatherObjectCloud.kt
Normal file
@@ -0,0 +1,137 @@
|
||||
package net.torvald.terrarum.weather
|
||||
|
||||
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.jme3.math.FastMath
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.math.sign
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-08-21.
|
||||
*/
|
||||
class WeatherObjectCloud(private val texture: TextureRegion, private val flipW: Boolean) : WeatherObject(), Comparable<WeatherObjectCloud> {
|
||||
|
||||
override fun update() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
var life = 0; private set
|
||||
var despawnCode = ""; private set
|
||||
|
||||
private val lifespan = 40000 + ((Math.random() + Math.random()) * 20000).roundToInt() // triangular distibution of 40000..80000
|
||||
|
||||
private fun getZflowMult(z: Float) = z / ((z / 4f).pow(1.5f))
|
||||
|
||||
private var eigenAlpha = 0f
|
||||
|
||||
/**
|
||||
* FlowVector: In which direction the cloud flows. Vec3(dX, dY, dScale)
|
||||
* Resulting vector: (x + dX, y + dY, scale * dScale)
|
||||
*/
|
||||
fun update(flowVector: Vector3) {
|
||||
pos.add(
|
||||
flowVector.cpy().
|
||||
scl(1f, 1f, getZflowMult(posZ)). // this will break the perspective if flowVector.z.abs() is close to 1, but it has to be here to "keep the distance"
|
||||
scl(vecMult)
|
||||
)
|
||||
|
||||
eigenAlpha = if (posZ < 1f) posZ.pow(0.5f) else -((posZ - 1f) / ALPHA_ROLLOFF_Z) + 1f
|
||||
|
||||
alpha = eigenAlpha * if (life < lifespan) 1f else 1f - (life - lifespan) / OLD_AGE_DECAY
|
||||
|
||||
|
||||
val lrCoord = screenCoordBottomLRforDespawnCalculation
|
||||
if (lrCoord.x > WeatherMixer.oobMarginR || lrCoord.z < WeatherMixer.oobMarginL || posZ !in 0.0001f..ALPHA_ROLLOFF_Z + 1f || alpha < 0f) {
|
||||
flagToDespawn = true
|
||||
|
||||
despawnCode = if (lrCoord.x > WeatherMixer.oobMarginR) "OUT_OF_SCREEN_RIGHT"
|
||||
else if (lrCoord.z < WeatherMixer.oobMarginL) "OUT_OF_SCREEN_LEFT"
|
||||
else if (posZ < 0.0001f) "OUT_OF_SCREEN_TOO_CLOSE"
|
||||
else if (posZ > ALPHA_ROLLOFF_Z + 1f) "OUT_OF_SCREEN_TOO_FAR"
|
||||
else if (life >= lifespan + OLD_AGE_DECAY) "OLD_AGE"
|
||||
else if (alpha < 0f) "ALPHA_BELOW_ZERO"
|
||||
else "UNKNOWN"
|
||||
}
|
||||
else {
|
||||
life += 1
|
||||
}
|
||||
}
|
||||
|
||||
private val w = App.scr.halfwf
|
||||
private val h = App.scr.hf * 0.5f
|
||||
private val vecMult = Vector3(1f, 1f, 1f / (4f * h))
|
||||
|
||||
/**
|
||||
* X/Y position is a bottom-centre point of the image
|
||||
* Shader must be prepared prior to the render() call
|
||||
*/
|
||||
override fun render(batch: SpriteBatch, offsetX: Float, offsetY: Float) {
|
||||
val sc = screenCoord
|
||||
|
||||
if (flipW)
|
||||
batch.draw(texture, sc.x + texture.regionWidth / posZ, sc.y, -texture.regionWidth * sc.z, texture.regionHeight * sc.z)
|
||||
else
|
||||
batch.draw(texture, sc.x, sc.y, texture.regionWidth * sc.z, texture.regionHeight * sc.z)
|
||||
}
|
||||
|
||||
/**
|
||||
* vec3(screen X, screenY, draw scale)
|
||||
*/
|
||||
val screenCoord: Vector3
|
||||
get() {
|
||||
val x = posX - texture.regionWidth * scale * 0.5f
|
||||
val y = posY - texture.regionHeight * scale
|
||||
val z = posZ // must be at least 1.0
|
||||
|
||||
val drawX = (x + w * (z-1)) / z
|
||||
val drawY = (y + h * (z-1)) / z
|
||||
val drawScale = scale / z
|
||||
|
||||
return Vector3(drawX, drawY, drawScale)
|
||||
}
|
||||
|
||||
/**
|
||||
* vec3(screen-X of bottom-left point, screen-Y, screen-X of bottom-right point)
|
||||
*/
|
||||
val screenCoordBottomLR: Vector3
|
||||
get() {
|
||||
val xL = posX - texture.regionWidth * scale * 0.5f
|
||||
val xR = posX + texture.regionWidth * scale * 0.5f
|
||||
val y = posY - texture.regionHeight * scale
|
||||
val z = posZ // must be larger than 0
|
||||
|
||||
val drawXL = (xL + w * (z-1)) / z
|
||||
val drawXR = (xR + w * (z-1)) / z
|
||||
val drawY = (y + h * (z-1)) / z
|
||||
|
||||
return Vector3(drawXL, drawY, drawXR)
|
||||
}
|
||||
|
||||
private val screenCoordBottomLRforDespawnCalculation: Vector3
|
||||
get() {
|
||||
val xL = posX - texture.regionWidth * scale * 0.5f
|
||||
val xR = posX + texture.regionWidth * scale * 0.5f
|
||||
val y = posY - texture.regionHeight * scale
|
||||
val z = FastMath.interpolateLinear(posZ / ALPHA_ROLLOFF_Z, ALPHA_ROLLOFF_Z / 4f, ALPHA_ROLLOFF_Z)
|
||||
|
||||
val drawXL = (xL + w * (z-1)) / z
|
||||
val drawXR = (xR + w * (z-1)) / z
|
||||
val drawY = (y + h * (z-1)) / z
|
||||
|
||||
return Vector3(drawXL, drawY, drawXR)
|
||||
}
|
||||
|
||||
override fun dispose() { /* cloud texture will be disposed of by the WeatherMixer */ }
|
||||
override fun compareTo(other: WeatherObjectCloud): Int = (other.posZ - this.posZ).sign.toInt()
|
||||
|
||||
companion object {
|
||||
fun screenXtoWorldX(screenX: Float, z: Float) = screenX * z - App.scr.halfwf * (z - 1f)
|
||||
const val ALPHA_ROLLOFF_Z = 64f
|
||||
const val OLD_AGE_DECAY = 4000f
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,9 @@ object WorldCamera {
|
||||
var worldHeight = 0
|
||||
private set
|
||||
|
||||
inline val camVector: com.badlogic.gdx.math.Vector2
|
||||
get() = com.badlogic.gdx.math.Vector2(gdxCamX, gdxCamY)
|
||||
|
||||
fun update(world: GameWorld, player: ActorWithBody?) {
|
||||
if (player == null) return
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#version 150
|
||||
#version 400
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
@@ -16,5 +16,6 @@ const vec2 boolean = vec2(0.0, 1.0);
|
||||
void main(void) {
|
||||
vec4 colorTex0 = texture(u_texture, v_texCoords); // lightmap (RGB) pre-mixed
|
||||
vec4 colorTex1 = texture(tex1, v_texCoords); // lightmap (A) pre-mixed
|
||||
fragColor = (max(colorTex0, colorTex1) * boolean.yyyx) + (colorTex0 * boolean.xxxy);
|
||||
// fragColor = (max(colorTex0, colorTex1) * boolean.yyyx) + (colorTex0 * boolean.xxxy);
|
||||
fragColor = fma(max(colorTex0, colorTex1), boolean.yyyx, colorTex0 * boolean.xxxy);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#version 150
|
||||
#version 400
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
@@ -150,7 +150,10 @@ void main(void) {
|
||||
); // c = c0..c1
|
||||
|
||||
|
||||
fragColor = (max(colorTex0, colorTex1) * boolean.yyyx) + boolean.xxxy;
|
||||
// fragColor = (max(colorTex0, colorTex1) * boolean.yyyx) + boolean.xxxy;
|
||||
fragColor = fma(max(colorTex0, colorTex1), boolean.yyyx, boolean.xxxy);
|
||||
|
||||
|
||||
// fragColor = colorTex1;
|
||||
// fragColor = randomness * boolean.yyyx + boolean.xxxy;
|
||||
// fragColor = (randomness.rrrr + (colorTex1 * vec4(2.0, -2.0, 2.0, 1.0))) * boolean.yyyx + boolean.xxxy;
|
||||
|
||||
30
src/shaders/clouds.frag
Normal file
30
src/shaders/clouds.frag
Normal file
@@ -0,0 +1,30 @@
|
||||
#version 400
|
||||
|
||||
#ifdef GL_ES
|
||||
#define LOWP lowp
|
||||
precision mediump float;
|
||||
#else
|
||||
#define LOWP
|
||||
#endif
|
||||
|
||||
in LOWP vec4 v_color; // lightCol.rgb + cloud's alpha
|
||||
in vec2 v_texCoords;
|
||||
uniform sampler2D u_texture;
|
||||
out vec4 fragColor;
|
||||
|
||||
const vec2 boolean = vec2(0.0, 1.0);
|
||||
|
||||
uniform vec2 gamma = vec2(10, 2.0); // vec2(gamma for RGB, gamma for A)
|
||||
|
||||
uniform LOWP vec4 shadeCol;
|
||||
|
||||
void main() {
|
||||
// r: bw diffuse map, g: normal, b: normal, a: bw diffuse alpha
|
||||
vec4 inCol = texture(u_texture, v_texCoords);
|
||||
vec4 rawCol = pow(inCol, gamma.xxxy);
|
||||
|
||||
// do gradient mapping here
|
||||
vec4 outCol = fma(mix(shadeCol, v_color, rawCol.r), boolean.yyyx, rawCol * boolean.xxxy);
|
||||
|
||||
fragColor = outCol * fma(v_color, boolean.xxxy, boolean.yyyx);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#version 150
|
||||
#version 400
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
@@ -41,7 +41,8 @@ vec4 getDitherredDot(vec4 inColor) {
|
||||
|
||||
|
||||
void main(void) {
|
||||
float scale = v_texCoords.y * (1.0 - parallax_size) + (parallax_size / 2.0) + (parallax * parallax_size / 2.0);
|
||||
float parallaxAdder = 0.5 * (parallax + 1.0) * parallax_size;
|
||||
float scale = fma(v_texCoords.y, 1.0 - parallax_size, parallaxAdder);
|
||||
|
||||
float zoomSamplePoint = (1.0 - zoomInv) / 2.0;// will never quite exceed 0.5
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#version 150
|
||||
#version 400
|
||||
in vec4 v_color;
|
||||
in vec2 v_texCoords;
|
||||
uniform sampler2D u_texture;
|
||||
@@ -11,5 +11,6 @@ void main(void) {
|
||||
vec4 incolour = texture(u_texture, v_texCoords);
|
||||
float lum = dot(incolour * desaturate, boolean.yyyx) * 0.5 + 0.5;
|
||||
|
||||
fragColor = v_color * (vec4(lum) * boolean.yyyx + incolour * boolean.xxxy);
|
||||
// fragColor = v_color * (vec4(lum) * boolean.yyyx + incolour * boolean.xxxy);
|
||||
fragColor = v_color * fma(vec4(lum), boolean.yyyx, incolour * boolean.xxxy);
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* http://momentsingraphics.de/BlueNoise.html
|
||||
*/
|
||||
|
||||
#version 150
|
||||
#version 400
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
@@ -79,7 +79,7 @@ void main(void) {
|
||||
// Dither the output
|
||||
vec4 graded = ycocg_to_rgb * newColour;
|
||||
vec4 selvec = getDitherredDot(graded);
|
||||
vec4 outcol = selvec * boolean.yyyx + boolean.xxxy; // use quantised RGB but not the A
|
||||
vec4 outcol = fma(selvec, boolean.yyyx, boolean.xxxy); // use quantised RGB but not the A
|
||||
|
||||
fragColor = outcol;
|
||||
// ivec4 bytes = ivec4(255.0 * outcol);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* http://momentsingraphics.de/BlueNoise.html
|
||||
*/
|
||||
|
||||
#version 150
|
||||
#version 400
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
@@ -60,5 +60,5 @@ void main(void) {
|
||||
|
||||
// Dither the output
|
||||
vec4 graded = ycocg_to_rgb * newColour;
|
||||
fragColor = graded * boolean.yyyx + boolean.xxxy; // use quantised RGB but not the A
|
||||
fragColor = fma(graded, boolean.yyyx, boolean.xxxy); // use quantised RGB but not the A
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
*/
|
||||
|
||||
#version 150
|
||||
#version 400
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
@@ -107,7 +107,7 @@ void main() {
|
||||
|
||||
vec4 finalBreakage = drawBreakage * texture(tilesAtlas, finalUVCoordForBreakage); // drawBreakeage = 0 to not draw, = 1 to draw
|
||||
|
||||
vec4 finalColor =mix(finalTile, finalBreakage, finalBreakage.a) * bc.xxxy + (finalTile * bc.yyyx);
|
||||
vec4 finalColor = fma(mix(finalTile, finalBreakage, finalBreakage.a), bc.xxxy, finalTile * bc.yyyx);
|
||||
|
||||
fragColor = mix(colourFilter, colourFilter * finalColor, mulBlendIntensity);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
*/
|
||||
|
||||
#version 150
|
||||
#version 400
|
||||
#ifdef GL_ES
|
||||
precision mediump float;
|
||||
#endif
|
||||
@@ -121,5 +121,5 @@ void main() {
|
||||
vec2 entry = mod(gl_FragCoord.xy, vec2(bayerSize, bayerSize));
|
||||
float bayerThreshold = float(bayer[int(entry.y) * int(bayerSize) + int(entry.x)]) / bayerDivider;
|
||||
|
||||
fragColor = undithered * bc.xxxy + vec4((undithered.a > bayerThreshold) ? 1.0 : 0.0) * bc.yyyx;
|
||||
fragColor = fma(undithered, bc.xxxy, vec4((undithered.a > bayerThreshold) ? 1.0 : 0.0) * bc.yyyx);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user