mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-06 16:44:05 +09:00
Compare commits
58 Commits
v0.3.2-tes
...
v0.3.2-tes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
453459e3b6 | ||
|
|
bad72dd353 | ||
|
|
13185f0565 | ||
|
|
fcaf4c97f1 | ||
|
|
9c396e7b8d | ||
|
|
afb7dff5d2 | ||
|
|
5d0514040c | ||
|
|
7c1806946b | ||
|
|
e5e02681b8 | ||
|
|
6db3baf691 | ||
|
|
07cbcbe79b | ||
|
|
57a9f7febc | ||
|
|
16cfaaea27 | ||
|
|
72c742897e | ||
|
|
23af64deb4 | ||
|
|
bb017fa9b7 | ||
|
|
1745bb16db | ||
|
|
370583d1af | ||
|
|
66b651c627 | ||
|
|
c5874a7f3d | ||
|
|
057905c3b7 | ||
|
|
2b50562002 | ||
|
|
73a8198378 | ||
|
|
1ef479124e | ||
|
|
e5e8028b3f | ||
|
|
739b51af95 | ||
|
|
f9f49ab63c | ||
|
|
a497463349 | ||
|
|
253db56c4f | ||
|
|
3d13941060 | ||
|
|
592e489411 | ||
|
|
49b2011ea0 | ||
|
|
61e6255b52 | ||
|
|
2e956f89f5 | ||
|
|
e8ffd1f844 | ||
|
|
0882145f9c | ||
|
|
28e2179e44 | ||
|
|
48eb1ffd8f | ||
|
|
6daccb2e62 | ||
|
|
8c9d5a26fb | ||
|
|
ee3e5b14cd | ||
|
|
5c39df9080 | ||
|
|
5d77694316 | ||
|
|
cf111d2507 | ||
|
|
724ace3f00 | ||
|
|
1457cbffb3 | ||
|
|
7a42066392 | ||
|
|
528b975350 | ||
|
|
9e9064dd55 | ||
|
|
138c6d22d2 | ||
|
|
a33f0e7ab4 | ||
|
|
93c427473d | ||
|
|
6b8798a19e | ||
|
|
376595d7cd | ||
|
|
4cc52b5585 | ||
|
|
0ff71f39fe | ||
|
|
13f487a562 | ||
|
|
0599ce91b1 |
24
.idea/artifacts/TerrarumBuild.xml
generated
24
.idea/artifacts/TerrarumBuild.xml
generated
@@ -13,6 +13,10 @@
|
|||||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/gdx-controllers-desktop-2.2.1.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/gdx-controllers-desktop-2.2.1.jar" path-in-jar="/" />
|
||||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/GetCpuName.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/GetCpuName.jar" path-in-jar="/" />
|
||||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/jxinput-1.0.0.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/jxinput-1.0.0.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-stdlib.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-reflect.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk7.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk8.jar" path-in-jar="/" />
|
||||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/commons-csv-1.8.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/commons-csv-1.8.jar" path-in-jar="/" />
|
||||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/prtree.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/prtree.jar" path-in-jar="/" />
|
||||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/Terrarum_Joise.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/Terrarum_Joise.jar" path-in-jar="/" />
|
||||||
@@ -72,21 +76,17 @@
|
|||||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/gdx-platform-1.11.0-natives-armeabi-v7a.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/gdx-platform-1.11.0-natives-armeabi-v7a.jar" path-in-jar="/" />
|
||||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/gdx-platform-1.11.0-natives-desktop.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/gdx-platform-1.11.0-natives-desktop.jar" path-in-jar="/" />
|
||||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/gdx-platform-1.11.0-natives-x86_64.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/gdx-platform-1.11.0-natives-x86_64.jar" path-in-jar="/" />
|
||||||
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.8.21/kotlin-stdlib-1.8.21.jar" path-in-jar="/" />
|
|
||||||
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" path-in-jar="/" />
|
|
||||||
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.8.21/kotlin-stdlib-common-1.8.21.jar" path-in-jar="/" />
|
|
||||||
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-test/1.8.21/kotlin-test-1.8.21.jar" path-in-jar="/" />
|
|
||||||
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.8.21/kotlin-reflect-1.8.21.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.8.21/kotlin-reflect-1.8.21.jar" path-in-jar="/" />
|
||||||
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk8.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.8.21/kotlin-stdlib-1.8.21.jar" path-in-jar="/" />
|
||||||
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-reflect.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.8.21/kotlin-stdlib-common-1.8.21.jar" path-in-jar="/" />
|
||||||
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk7.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" path-in-jar="/" />
|
||||||
<element id="extracted-dir" path="$KOTLIN_BUNDLED$/lib/kotlin-stdlib.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-test/1.8.21/kotlin-test-1.8.21.jar" path-in-jar="/" />
|
||||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/graal-sdk-22.3.1.jar" path-in-jar="/" />
|
|
||||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/icu4j-71.1.jar" path-in-jar="/" />
|
|
||||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/js-22.3.1-edit.jar" path-in-jar="/" />
|
|
||||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/js-scriptengine-22.3.1.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/js-scriptengine-22.3.1.jar" path-in-jar="/" />
|
||||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/regex-22.3.1-edit.jar" path-in-jar="/" />
|
|
||||||
<element id="extracted-dir" path="$PROJECT_DIR$/lib/truffle-api-22.3.1.jar" path-in-jar="/" />
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/truffle-api-22.3.1.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/icu4j-71.1.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/regex-22.3.1-edit.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/js-22.3.1-edit.jar" path-in-jar="/" />
|
||||||
|
<element id="extracted-dir" path="$PROJECT_DIR$/lib/graal-sdk-22.3.1.jar" path-in-jar="/" />
|
||||||
</root>
|
</root>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
19
.idea/runConfigurations/Principii.xml
generated
Normal file
19
.idea/runConfigurations/Principii.xml
generated
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Principii" type="Application" factoryName="Application" nameIsGenerated="true">
|
||||||
|
<option name="MAIN_CLASS_NAME" value="net.torvald.terrarum.Principii" />
|
||||||
|
<module name="TerrarumBuild" />
|
||||||
|
<extension name="coverage">
|
||||||
|
<pattern>
|
||||||
|
<option name="PATTERN" value="net.torvald.terrarum.*" />
|
||||||
|
<option name="ENABLED" value="true" />
|
||||||
|
</pattern>
|
||||||
|
</extension>
|
||||||
|
<method v="2">
|
||||||
|
<option name="BuildArtifacts" enabled="true">
|
||||||
|
<artifact name="ModuleComputers" />
|
||||||
|
<artifact name="TerrarumBuild" />
|
||||||
|
</option>
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -195,17 +195,10 @@ internal class UIHomeComputer : UICanvas(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun doOpening(delta: Float) {
|
override fun doOpening(delta: Float) {
|
||||||
|
super.doOpening(delta)
|
||||||
fixture.startVM()
|
fixture.startVM()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun doClosing(delta: Float) {
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun endOpening(delta: Float) {
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun endClosing(delta: Float) {
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
fbo.dispose()
|
fbo.dispose()
|
||||||
|
|||||||
BIN
assets/graphics/gui/apple_rosetta_warning.tga
LFS
Normal file
BIN
assets/graphics/gui/apple_rosetta_warning.tga
LFS
Normal file
Binary file not shown.
@@ -7,12 +7,10 @@
|
|||||||
"MENU_LABEL_PRESS_START_SYMBOL": "Press >",
|
"MENU_LABEL_PRESS_START_SYMBOL": "Press >",
|
||||||
"MENU_MODULES" : "Modules",
|
"MENU_MODULES" : "Modules",
|
||||||
"MENU_CREDIT_GPL_DNT" : "GPL",
|
"MENU_CREDIT_GPL_DNT" : "GPL",
|
||||||
|
"MENU_LABEL_JVM_DNT" : "JVM",
|
||||||
"GAME_ACTION_MOVE_VERB" : "Move",
|
"GAME_ACTION_MOVE_VERB" : "Move",
|
||||||
"GAME_ACTION_ZOOM" : "Zoom",
|
"GAME_ACTION_ZOOM" : "Zoom",
|
||||||
"MENU_LABEL_RESET" : "Reset",
|
"MENU_LABEL_RESET" : "Reset",
|
||||||
"GAME_32BIT_WARNING1": "It looks like you’re running a 32-Bit version of Java.",
|
|
||||||
"GAME_32BIT_WARNING2": "Please download and install the latest 64-Bit Java at:",
|
|
||||||
"GAME_32BIT_WARNING3": "https://www.java.com/en/download/",
|
|
||||||
"MENU_OPTION_STREAMERS_LAYOUT": "Chat Overlay",
|
"MENU_OPTION_STREAMERS_LAYOUT": "Chat Overlay",
|
||||||
"MENU_LABEL_RESTART_REQUIRED": "Restart Required",
|
"MENU_LABEL_RESTART_REQUIRED": "Restart Required",
|
||||||
"MENU_LABEL_KEYBOARD_LAYOUT": "Keyboard Layout",
|
"MENU_LABEL_KEYBOARD_LAYOUT": "Keyboard Layout",
|
||||||
@@ -21,11 +19,19 @@
|
|||||||
"MENU_OPTIONS_BLUR": "Blur",
|
"MENU_OPTIONS_BLUR": "Blur",
|
||||||
"MENU_OPTIONS_PARTICLES": "Particles",
|
"MENU_OPTIONS_PARTICLES": "Particles",
|
||||||
"MENU_IO_IMPORT": "Import",
|
"MENU_IO_IMPORT": "Import",
|
||||||
"APP_NOMODULE_1": "No Module is currently loaded.",
|
|
||||||
"APP_NOMODULE_2": "Please configure your Load Order and restart:",
|
|
||||||
"MENU_LABEL_KEYCONFIG_HELP1": "Click On the Keycap to Assign Actions",
|
|
||||||
"MENU_LABEL_IME_TOGGLE": "Toggle IME",
|
"MENU_LABEL_IME_TOGGLE": "Toggle IME",
|
||||||
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "Paste from Cliboard",
|
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "Paste from Clipboard",
|
||||||
"MENU_OPTIONS_PERFORMANCE": "Performance",
|
"MENU_OPTIONS_PERFORMANCE": "Performance",
|
||||||
"MENU_LABEL_DELETE": "Delete"
|
"MENU_LABEL_DELETE": "Delete",
|
||||||
|
"MENU_OPTIONS_JVM_HEAP_MAX": "Max Heap Memory",
|
||||||
|
"MENU_OPTIONS_AUTOSAVE": "Autosave",
|
||||||
|
"CONTEXT_TIME_MINUTE_PLURAL": "Minutes",
|
||||||
|
"CONTEXT_TIME_SECOND_PLURAL": "Seconds",
|
||||||
|
"MENU_LABEL_SYSTEM_INFO": "System Info",
|
||||||
|
"MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION": "Show notification for",
|
||||||
|
"MENU_LABEL_STREAMING": "Livestreaming",
|
||||||
|
"MENU_LABEL_EXTRA_JVM_ARGUMENTS": "Extra Arguments",
|
||||||
|
"MENU_IO_MANUAL_SAVE": "Manual Save",
|
||||||
|
"MENU_IO_AUTOSAVE": "Autosave",
|
||||||
|
"MENU_OPTIONS_DEBUG_CONSOLE": "Debug Console"
|
||||||
}
|
}
|
||||||
16
assets/locales/en/terrarum_sentences.json
Normal file
16
assets/locales/en/terrarum_sentences.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"GAME_32BIT_WARNING1": "32비트 버전의 Java를 사용중인 것 같습니다.",
|
||||||
|
"GAME_32BIT_WARNING2": "아래 링크에서 최신 64비트 Java를 내려받아 설치해주세요.",
|
||||||
|
"GAME_32BIT_WARNING3": "https://www.java.com/ko/download/",
|
||||||
|
"GAME_APPLE_ROSETTA_WARNING1": "Apple Silicon이 탑재된 Mac을 사용 중이지만 x86 빌드의 게임을 실행 중입니다.",
|
||||||
|
"GAME_APPLE_ROSETTA_WARNING2": "최적의 성능과 게임 경험을 위해 Apple Silicon용 빌드의 게임을 이용해 주십시오.",
|
||||||
|
"APP_NOMODULE_1": "현재 불러와진 모듈이 없습니다.",
|
||||||
|
"APP_NOMODULE_2": "다음의 파일에서 불러오기 순서를 설정하고 게임을 재시작하십시오.",
|
||||||
|
"MENU_LABEL_KEYCONFIG_HELP1": "키캡을 클릭해 컨트롤을 배정하십시오",
|
||||||
|
"GAME_PREV_SAVE_WAS_LOADED1": "가장 최근에 저장된 게임이 손상되었습니다.",
|
||||||
|
"GAME_PREV_SAVE_WAS_LOADED2": "이전에 저장된 게임을 불러왔습니다.",
|
||||||
|
"GAME_MORE_RECENT_AUTOSAVE1": "자동 저장된 게임이 수동으로 저장한 게임보다 더 최신입니다.",
|
||||||
|
"GAME_MORE_RECENT_AUTOSAVE2": "불러올 게임을 선택해 주십시오.",
|
||||||
|
"MENU_LABEL_SAVE_WILL_BE_DELETED": "선택된 세이브가 삭제됩니다.",
|
||||||
|
"MENU_LABEL_UNSAVED_PROGRESSES_WILL_BE_LOST": "저장하지 않은 변동사항을 잃게 됩니다."
|
||||||
|
}
|
||||||
@@ -2335,7 +2335,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"n": "MENU_OPTIONS",
|
"n": "MENU_OPTIONS",
|
||||||
"s": "Stillingar "
|
"s": "Valkostir "
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"n": "MENU_OPTIONS_ADVANCEDGRAPHICS",
|
"n": "MENU_OPTIONS_ADVANCEDGRAPHICS",
|
||||||
@@ -2395,11 +2395,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"n": "MENU_OPTIONS_GAMEPLAY",
|
"n": "MENU_OPTIONS_GAMEPLAY",
|
||||||
"s": "Gameplay Options"
|
"s": "Leikvalkostir"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"n": "MENU_OPTIONS_GRAPHICS",
|
"n": "MENU_OPTIONS_GRAPHICS",
|
||||||
"s": "Grafíkstillingar"
|
"s": "Grafíkvalkostir"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"n": "MENU_OPTIONS_HUD",
|
"n": "MENU_OPTIONS_HUD",
|
||||||
|
|||||||
@@ -15,5 +15,15 @@
|
|||||||
"MENU_OPTIONS_DITHER": "Dither",
|
"MENU_OPTIONS_DITHER": "Dither",
|
||||||
"MENU_OPTIONS_BLUR": "Óskýrt",
|
"MENU_OPTIONS_BLUR": "Óskýrt",
|
||||||
"MENU_OPTIONS_PARTICLES": "Eind",
|
"MENU_OPTIONS_PARTICLES": "Eind",
|
||||||
"MENU_IO_IMPORT": "Flytja inn"
|
"MENU_IO_IMPORT": "Flytja inn",
|
||||||
|
"APP_NOMODULE_1": "Engin eining er hlaðin eins og er.",
|
||||||
|
"APP_NOMODULE_2": "Vinsamlega stilltu hleðslupöntunina þína og endurræstu:",
|
||||||
|
"MENU_LABEL_KEYCONFIG_HELP1": "Smelltu á lyklalokið til að úthluta aðgerðum",
|
||||||
|
"MENU_LABEL_IME_TOGGLE": "Breyttu IME",
|
||||||
|
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "Límdu frá klemmuspjald",
|
||||||
|
"MENU_OPTIONS_PERFORMANCE": "Afköst",
|
||||||
|
"MENU_LABEL_DELETE": "Eyða",
|
||||||
|
"MENU_OPTIONS_JVM_HEAP_MAX": "Hámarks hrúguminni",
|
||||||
|
"MENU_OPTIONS_AUTOSAVE": "Sjálfvirk vistun",
|
||||||
|
"CONTEXT_TIME_MINUTE_PLURAL": "Mínútur"
|
||||||
}
|
}
|
||||||
@@ -6,12 +6,11 @@
|
|||||||
"APP_WARNING_HEALTH_AND_SAFETY": "경고—건강과 안전을 위하여",
|
"APP_WARNING_HEALTH_AND_SAFETY": "경고—건강과 안전을 위하여",
|
||||||
"MENU_LABEL_PRESS_START_SYMBOL": ">을 누르세요",
|
"MENU_LABEL_PRESS_START_SYMBOL": ">을 누르세요",
|
||||||
"MENU_MODULES" : "모듈",
|
"MENU_MODULES" : "모듈",
|
||||||
|
|
||||||
|
|
||||||
"GAME_ACTION_MOVE_VERB" : "이동하기",
|
"GAME_ACTION_MOVE_VERB" : "이동하기",
|
||||||
"GAME_ACTION_ZOOM" : "확대·축소",
|
"GAME_ACTION_ZOOM" : "확대·축소",
|
||||||
"MENU_LABEL_RESET" : "재설정",
|
"MENU_LABEL_RESET" : "재설정",
|
||||||
"GAME_32BIT_WARNING1": "32비트 버전의 Java를 사용중인 것 같습니다.",
|
|
||||||
"GAME_32BIT_WARNING2": "아래 링크에서 최신 64비트 Java를 내려받아 설치해주세요.",
|
|
||||||
"GAME_32BIT_WARNING3": "https://www.java.com/ko/download/",
|
|
||||||
"MENU_OPTION_STREAMERS_LAYOUT": "채팅창 오버레이",
|
"MENU_OPTION_STREAMERS_LAYOUT": "채팅창 오버레이",
|
||||||
"MENU_LABEL_RESTART_REQUIRED": "재시작 필요",
|
"MENU_LABEL_RESTART_REQUIRED": "재시작 필요",
|
||||||
"MENU_LABEL_KEYBOARD_LAYOUT": "자판 배열",
|
"MENU_LABEL_KEYBOARD_LAYOUT": "자판 배열",
|
||||||
@@ -20,10 +19,19 @@
|
|||||||
"MENU_OPTIONS_BLUR": "흐림",
|
"MENU_OPTIONS_BLUR": "흐림",
|
||||||
"MENU_OPTIONS_PARTICLES": "입자 수",
|
"MENU_OPTIONS_PARTICLES": "입자 수",
|
||||||
"MENU_IO_IMPORT": "가져오기",
|
"MENU_IO_IMPORT": "가져오기",
|
||||||
"APP_NOMODULE_1": "현재 불러와진 모듈이 없습니다.",
|
|
||||||
"APP_NOMODULE_2": "다음의 파일에서 불러오기 순서를 설정하고 게임을 재시작하십시오.",
|
|
||||||
"MENU_LABEL_KEYCONFIG_HELP1": "키캡을 클릭해 컨트롤을 배정하십시오",
|
|
||||||
"MENU_LABEL_IME_TOGGLE": "입력기 켜고 끄기",
|
"MENU_LABEL_IME_TOGGLE": "입력기 켜고 끄기",
|
||||||
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "복사한 텍스트 붙여넣기",
|
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "복사한 텍스트 붙여넣기",
|
||||||
"MENU_OPTIONS_PERFORMANCE": "성능"
|
"MENU_OPTIONS_PERFORMANCE": "성능",
|
||||||
|
"MENU_LABEL_DELETE": "삭제",
|
||||||
|
"MENU_OPTIONS_JVM_HEAP_MAX": "최대 힙 메모리",
|
||||||
|
"MENU_OPTIONS_AUTOSAVE": "자동 저장",
|
||||||
|
"CONTEXT_TIME_MINUTE_PLURAL": "분",
|
||||||
|
"CONTEXT_TIME_SECOND_PLURAL": "초",
|
||||||
|
"MENU_LABEL_SYSTEM_INFO": "시스템 정보",
|
||||||
|
"MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION": "알림 표시 시간",
|
||||||
|
"MENU_LABEL_STREAMING": "실시간 방송",
|
||||||
|
"MENU_LABEL_EXTRA_JVM_ARGUMENTS": "추가 명령 인수",
|
||||||
|
"MENU_IO_MANUAL_SAVE": "수동 저장",
|
||||||
|
"MENU_IO_AUTOSAVE": "자동 저장",
|
||||||
|
"MENU_OPTIONS_DEBUG_CONSOLE": "디버그 콘솔"
|
||||||
}
|
}
|
||||||
|
|||||||
15
assets/locales/koKR/terrarum_sentences.json
Normal file
15
assets/locales/koKR/terrarum_sentences.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"GAME_32BIT_WARNING1": "32비트 버전의 Java를 사용중인 것 같습니다.",
|
||||||
|
"GAME_32BIT_WARNING2": "아래 링크에서 최신 64비트 Java를 내려받아 설치해주세요.",
|
||||||
|
"GAME_32BIT_WARNING3": "https://www.java.com/ko/download/",
|
||||||
|
"GAME_APPLE_ROSETTA_WARNING1": "Apple Silicon이 탑재된 Mac을 사용 중이지만 x86 빌드의 게임을 실행 중입니다.",
|
||||||
|
"GAME_APPLE_ROSETTA_WARNING2": "최적의 성능과 게임 경험을 위해 Apple Silicon용 빌드의 게임을 이용해 주십시오.",
|
||||||
|
"APP_NOMODULE_1": "현재 불러와진 모듈이 없습니다.",
|
||||||
|
"APP_NOMODULE_2": "다음의 파일에서 불러오기 순서를 설정하고 게임을 재시작하십시오.",
|
||||||
|
"MENU_LABEL_KEYCONFIG_HELP1": "키캡을 클릭해 컨트롤을 배정하십시오",
|
||||||
|
"GAME_PREV_SAVE_WAS_LOADED1": "가장 최근에 저장된 게임이 손상되었습니다.",
|
||||||
|
"GAME_PREV_SAVE_WAS_LOADED2": "이전에 저장된 게임을 불러왔습니다.",
|
||||||
|
"GAME_MORE_RECENT_AUTOSAVE1": "자동 저장된 게임이 수동으로 저장한 게임보다 더 최신입니다.",
|
||||||
|
"GAME_MORE_RECENT_AUTOSAVE2": "불러올 게임을 선택해 주십시오.",
|
||||||
|
"MENU_LABEL_SAVE_WILL_BE_DELETED": "선택된 세이브가 삭제됩니다."
|
||||||
|
}
|
||||||
BIN
assets/mods/basegame/gui/backdrop01.tga
LFS
Normal file
BIN
assets/mods/basegame/gui/backdrop01.tga
LFS
Normal file
Binary file not shown.
@@ -17,7 +17,7 @@
|
|||||||
"GAME_ACTION_CRAFT": "Craft",
|
"GAME_ACTION_CRAFT": "Craft",
|
||||||
"GAME_CRAFTING": "Crafting",
|
"GAME_CRAFTING": "Crafting",
|
||||||
"GAME_CRAFTABLE_ITEMS": "Craftable Items",
|
"GAME_CRAFTABLE_ITEMS": "Craftable Items",
|
||||||
"CONTEXT_WORLD_SEARCH": "World Search",
|
"MENU_LABEL_RENAME": "Rename",
|
||||||
"CONTEXT_WORLD_LIST": "Worlds List",
|
"GAME_ACTION_TELEPORT": "Teleport",
|
||||||
"MENU_LABEL_RENAME": "Rename"
|
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "This is a world currently playing."
|
||||||
}
|
}
|
||||||
@@ -17,5 +17,8 @@
|
|||||||
"GAME_ACTION_QUICKSEL": "빠른 선택",
|
"GAME_ACTION_QUICKSEL": "빠른 선택",
|
||||||
"GAME_ACTION_CRAFT": "제작하기",
|
"GAME_ACTION_CRAFT": "제작하기",
|
||||||
"GAME_CRAFTING": "제작",
|
"GAME_CRAFTING": "제작",
|
||||||
"GAME_CRAFTABLE_ITEMS": "제작 가능한 아이템"
|
"GAME_CRAFTABLE_ITEMS": "제작 가능한 아이템",
|
||||||
|
"MENU_LABEL_RENAME": "이름 바꾸기",
|
||||||
|
"GAME_ACTION_TELEPORT": "텔레포트하기",
|
||||||
|
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "현재 플레이 중인 월드입니다."
|
||||||
}
|
}
|
||||||
@@ -23,12 +23,13 @@ cp $SRCFILES/AppRun $DESTDIR/AppRun
|
|||||||
chmod +x $DESTDIR/AppRun
|
chmod +x $DESTDIR/AppRun
|
||||||
|
|
||||||
# Copy over a Java runtime
|
# Copy over a Java runtime
|
||||||
cp -r "../out/$RUNTIME" $DESTDIR/
|
mkdir $DESTDIR/out
|
||||||
|
cp -r "../out/$RUNTIME" $DESTDIR/out/
|
||||||
|
|
||||||
# Copy over all the assets and a jarfile
|
# Copy over all the assets and a jarfile
|
||||||
cp -r "../assets_release" $DESTDIR/
|
cp -r "../assets_release" $DESTDIR/
|
||||||
mv $DESTDIR/assets_release $DESTDIR/assets
|
mv $DESTDIR/assets_release $DESTDIR/assets
|
||||||
cp -r "../out/TerrarumBuild.jar" $DESTDIR/assets/
|
cp "../out/TerrarumBuild.jar" $DESTDIR/out/
|
||||||
|
|
||||||
# Pack everything to AppImage
|
# Pack everything to AppImage
|
||||||
ARCH=arm_aarch64 "./$APPIMAGETOOL" $DESTDIR "out/$DESTDIR.AppImage" || { echo 'Building AppImage failed' >&2; exit 1; }
|
ARCH=arm_aarch64 "./$APPIMAGETOOL" $DESTDIR "out/$DESTDIR.AppImage" || { echo 'Building AppImage failed' >&2; exit 1; }
|
||||||
|
|||||||
@@ -23,12 +23,13 @@ cp $SRCFILES/AppRun $DESTDIR/AppRun
|
|||||||
chmod +x $DESTDIR/AppRun
|
chmod +x $DESTDIR/AppRun
|
||||||
|
|
||||||
# Copy over a Java runtime
|
# Copy over a Java runtime
|
||||||
cp -r "../out/$RUNTIME" $DESTDIR/
|
mkdir $DESTDIR/out
|
||||||
|
cp -r "../out/$RUNTIME" $DESTDIR/out/
|
||||||
|
|
||||||
# Copy over all the assets and a jarfile
|
# Copy over all the assets and a jarfile
|
||||||
cp -r "../assets_release" $DESTDIR/
|
cp -r "../assets_release" $DESTDIR/
|
||||||
mv $DESTDIR/assets_release $DESTDIR/assets
|
mv $DESTDIR/assets_release $DESTDIR/assets
|
||||||
cp -r "../out/TerrarumBuild.jar" $DESTDIR/assets/
|
cp "../out/TerrarumBuild.jar" $DESTDIR/out/
|
||||||
|
|
||||||
# Pack everything to AppImage
|
# Pack everything to AppImage
|
||||||
"./$APPIMAGETOOL" $DESTDIR "out/$DESTDIR.AppImage" || { echo 'Building AppImage failed' >&2; exit 1; }
|
"./$APPIMAGETOOL" $DESTDIR "out/$DESTDIR.AppImage" || { echo 'Building AppImage failed' >&2; exit 1; }
|
||||||
|
|||||||
@@ -25,11 +25,12 @@ cp $SRCFILES/Terrarum.sh $DESTDIR/Contents/MacOS/
|
|||||||
chmod +x $DESTDIR/Contents/MacOS/Terrarum.sh
|
chmod +x $DESTDIR/Contents/MacOS/Terrarum.sh
|
||||||
|
|
||||||
# Copy over a Java runtime
|
# Copy over a Java runtime
|
||||||
cp -r "../out/$RUNTIME" $DESTDIR/Contents/MacOS/
|
mkdir $DESTDIR/Contents/MacOS/out
|
||||||
|
cp -r "../out/$RUNTIME" $DESTDIR/Contents/MacOS/out/
|
||||||
|
|
||||||
# Copy over all the assets and a jarfile
|
# Copy over all the assets and a jarfile
|
||||||
cp -r "../assets_release" $DESTDIR/Contents/MacOS/
|
cp -r "../assets_release" $DESTDIR/Contents/MacOS/
|
||||||
mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets
|
mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets
|
||||||
cp -r "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/assets/
|
cp "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/out/
|
||||||
|
|
||||||
echo "Build successful: $DESTDIR"
|
echo "Build successful: $DESTDIR"
|
||||||
|
|||||||
@@ -25,11 +25,12 @@ cp $SRCFILES/Terrarum.sh $DESTDIR/Contents/MacOS/
|
|||||||
chmod +x $DESTDIR/Contents/MacOS/Terrarum.sh
|
chmod +x $DESTDIR/Contents/MacOS/Terrarum.sh
|
||||||
|
|
||||||
# Copy over a Java runtime
|
# Copy over a Java runtime
|
||||||
cp -r "../out/$RUNTIME" $DESTDIR/Contents/MacOS/
|
mkdir $DESTDIR/Contents/MacOS/out
|
||||||
|
cp -r "../out/$RUNTIME" $DESTDIR/Contents/MacOS/out/
|
||||||
|
|
||||||
# Copy over all the assets and a jarfile
|
# Copy over all the assets and a jarfile
|
||||||
cp -r "../assets_release" $DESTDIR/Contents/MacOS/
|
cp -r "../assets_release" $DESTDIR/Contents/MacOS/
|
||||||
mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets
|
mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets
|
||||||
cp -r "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/assets/
|
cp "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/out/
|
||||||
|
|
||||||
echo "Build successful: $DESTDIR"
|
echo "Build successful: $DESTDIR"
|
||||||
|
|||||||
@@ -16,15 +16,21 @@ rm -rf $DESTDIR || true
|
|||||||
mkdir $DESTDIR
|
mkdir $DESTDIR
|
||||||
|
|
||||||
# Prepare an application
|
# Prepare an application
|
||||||
cp $SRCFILES/Terrarum.bat $DESTDIR/
|
if ! command -v x86_64-w64-mingw32-gcc &> /dev/null
|
||||||
|
then
|
||||||
|
echo 'Mingw32 not found; please install mingw64-cross-gcc (or similar) to your system' >&2; exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
x86_64-w64-mingw32-gcc -o $DESTDIR/Terrarum.exe $SRCFILES/Terrarum.c || { echo 'Building EXE failed' >&2; exit 1; }
|
||||||
|
|
||||||
# Copy over a Java runtime
|
# Copy over a Java runtime
|
||||||
cp -r "../out/$RUNTIME" $DESTDIR/
|
mkdir $DESTDIR/out
|
||||||
|
cp -r "../out/$RUNTIME" $DESTDIR/out/
|
||||||
|
|
||||||
# Copy over all the assets and a jarfile
|
# Copy over all the assets and a jarfile
|
||||||
cp -r "../assets_release" $DESTDIR/
|
cp -r "../assets_release" $DESTDIR/
|
||||||
mv $DESTDIR/assets_release $DESTDIR/assets
|
mv $DESTDIR/assets_release $DESTDIR/assets
|
||||||
cp -r "../out/TerrarumBuild.jar" $DESTDIR/assets/
|
cp "../out/TerrarumBuild.jar" $DESTDIR/out/
|
||||||
|
|
||||||
# Temporary solution: zip everything
|
# Temporary solution: zip everything
|
||||||
zip -r -9 -l "out/TerrarumWindows.x86.zip" $DESTDIR
|
zip -r -9 -l "out/TerrarumWindows.x86.zip" $DESTDIR
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
cd "${0%/*}"
|
cd "${0%/*}"
|
||||||
./runtime-linux-arm/bin/java -Xms1G -Xmx6G -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./assets/TerrarumBuild.jar
|
./out/runtime-linux-arm/bin/java -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./out/TerrarumBuild.jar
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
cd "${0%/*}"
|
cd "${0%/*}"
|
||||||
./runtime-linux-x86/bin/java -Xms1G -Xmx6G -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./assets/TerrarumBuild.jar
|
./out/runtime-linux-x86/bin/java -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./out/TerrarumBuild.jar
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
cd "${0%/*}"
|
cd "${0%/*}"
|
||||||
./runtime-osx-arm/bin/java -XstartOnFirstThread -Xms1G -Xmx6G -jar ./assets/TerrarumBuild.jar
|
./out/runtime-osx-arm/bin/java -jar ./out/TerrarumBuild.jar
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
cd "${0%/*}"
|
cd "${0%/*}"
|
||||||
./runtime-osx-x86/bin/java -XstartOnFirstThread -Xms1G -Xmx6G -jar ./assets/TerrarumBuild.jar
|
./out/runtime-osx-x86/bin/java -jar ./out/TerrarumBuild.jar
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
cd /D "%~dp0"
|
|
||||||
.\runtime-windows-x86\bin\java -Xms1G -Xmx6G -jar .\assets\TerrarumBuild.jar
|
|
||||||
6
buildapp/terrarumwindows_x86/Terrarum.c
Normal file
6
buildapp/terrarumwindows_x86/Terrarum.c
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
return system(".\\out\\runtime-windows-x86\\bin\\java -jar .\\out\\TerrarumBuild.jar");
|
||||||
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
Manifest-Version: 1.0
|
Manifest-Version: 1.0
|
||||||
Main-Class: net.torvald.terrarum.App
|
Main-Class: net.torvald.terrarum.Principii
|
||||||
|
|
||||||
|
|||||||
@@ -231,6 +231,10 @@ final public class FastMath {
|
|||||||
return (float) (((c4 * u + c3) * u + c2) * u + c1);
|
return (float) (((c4 * u + c3) * u + c2) * u + c1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static float interpolateCatmullRom(float u, float p0, float p1, float p2, float p3) {
|
||||||
|
return interpolateCatmullRom(u, 0.5f, p0, p1, p2, p3);
|
||||||
|
}
|
||||||
|
|
||||||
/**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
|
/**Interpolate a spline between at least 4 control points following the Catmull-Rom equation.
|
||||||
* here is the interpolation matrix
|
* here is the interpolation matrix
|
||||||
* m = [ 0.0 1.0 0.0 0.0 ]
|
* m = [ 0.0 1.0 0.0 0.0 ]
|
||||||
@@ -316,24 +320,25 @@ final public class FastMath {
|
|||||||
|
|
||||||
|
|
||||||
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, 1f, 0f);
|
// return interpolateHermite(scale, p0, p1, p2, p3, 0f, 0f);
|
||||||
}
|
|
||||||
public static float interpolateHermite(float scale, float p0, float p1, float p2, float p3, float tension, float bias) {
|
|
||||||
float mu2 = scale * scale;
|
float mu2 = scale * scale;
|
||||||
float mu3 = mu2 * scale;
|
float mu3 = mu2 * scale;
|
||||||
|
float biasTensionTerms = 0.5f;//(1f + bias) * (1f - tension) / 2f;
|
||||||
|
|
||||||
float m0 = (p1 - p0) * (1f + bias) * (1f - tension) / 2f;
|
float m0 = (p1 - p0) * biasTensionTerms;
|
||||||
m0 += (p2 - p1) * (1f + bias) * (1f - tension) / 2f;
|
float mTemp = (p2 - p1) * biasTensionTerms;
|
||||||
float m1 = (p2 - p1) * (1f + bias) * (1f - tension) / 2f;
|
m0 += mTemp;
|
||||||
m1 += (p3 - p2) * (1f + bias) * (1f - tension) / 2f;
|
float m1 = mTemp;
|
||||||
|
m1 += (p3 - p2) * biasTensionTerms;
|
||||||
|
|
||||||
float a0 = 2 * mu3 - 3 * mu2 + 1;
|
float a0 = 2*mu3 - 3*mu2 + 1;
|
||||||
float a1 = mu3 - 2 * mu2 + scale;
|
float a1 = 1*mu3 - 2*mu2 + scale;
|
||||||
float a2 = mu3 - mu2;
|
float a2 = 1*mu3 - 1*mu2 + 0;
|
||||||
float a3 = -2 * mu3 + 3 * mu2;
|
float a3 = -2*mu3 + 3*mu2 + 0;
|
||||||
|
|
||||||
return a0 * p1 + a1 * m0 + a2 * m1 + a3 * p2;
|
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) {}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class XXHash32 {
|
|||||||
|
|
||||||
public static int hashGeoCoord(int x, int y) {
|
public static int hashGeoCoord(int x, int y) {
|
||||||
int p = ((x & 65535) << 16) | (y & 65535);
|
int p = ((x & 65535) << 16) | (y & 65535);
|
||||||
return hash(new byte[]{(byte) p, (byte)(p >>> 8), (byte)(p >>> 16), (byte)(p >>> 24)}, 10000);
|
return hash(new byte[]{(byte) p, (byte)(p >>> 8), (byte)(p >>> 16), (byte)(p >>> 24)}, x ^ y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int hash(byte[] data, int seed) {
|
public static int hash(byte[] data, int seed) {
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ package net.torvald.reflection
|
|||||||
/**
|
/**
|
||||||
* Created by minjaesong on 2023-03-25.
|
* Created by minjaesong on 2023-03-25.
|
||||||
*/
|
*/
|
||||||
fun Any.extortField(name: String): Any? { // yes I'm deliberately using negative words for the function name
|
inline fun <reified T> Any.extortField(name: String): T? { // yes I'm deliberately using negative words for the function name
|
||||||
return this.javaClass.getDeclaredField(name).let {
|
return this.javaClass.getDeclaredField(name).let {
|
||||||
it.isAccessible = true
|
it.isAccessible = true
|
||||||
it.get(this)
|
it.get(this) as T?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun Any.forceInvoke(name: String, params: Array<Any>): Any? { // yes I'm deliberately using negative words for the function name
|
inline fun <reified T> Any.forceInvoke(name: String, params: Array<Any>): T? { // yes I'm deliberately using negative words for the function name
|
||||||
return this.javaClass.getDeclaredMethod(name, *(params.map { it.javaClass }.toTypedArray())).let {
|
return this.javaClass.getDeclaredMethod(name, *(params.map { it.javaClass }.toTypedArray())).let {
|
||||||
it.isAccessible = true
|
it.isAccessible = true
|
||||||
it.invoke(this, *params)
|
it.invoke(this, *params) as T?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,6 +142,12 @@ public class App implements ApplicationListener {
|
|||||||
|
|
||||||
public static final int GLOBAL_FRAMERATE_LIMIT = 300;
|
public static final int GLOBAL_FRAMERATE_LIMIT = 300;
|
||||||
|
|
||||||
|
private static String undesirableConditions;
|
||||||
|
|
||||||
|
public static String getUndesirableConditions() {
|
||||||
|
return undesirableConditions;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These languages won't distinguish regional differences (e.g. enUS and enUK, frFR and frCA)
|
* These languages won't distinguish regional differences (e.g. enUS and enUK, frFR and frCA)
|
||||||
*/
|
*/
|
||||||
@@ -201,11 +207,11 @@ public class App implements ApplicationListener {
|
|||||||
* Sorted by the lastplaytime, in reverse order (index 0 is the most recent game played)
|
* Sorted by the lastplaytime, in reverse order (index 0 is the most recent game played)
|
||||||
*/
|
*/
|
||||||
public static ArrayList<UUID> sortedSavegameWorlds = new ArrayList();
|
public static ArrayList<UUID> sortedSavegameWorlds = new ArrayList();
|
||||||
public static HashMap<UUID, DiskSkimmer> savegameWorlds = new HashMap<>(); // UNSORTED even with the TreeMap
|
public static HashMap<UUID, SavegameCollection> savegameWorlds = new HashMap<>(); // UNSORTED even with the TreeMap
|
||||||
public static HashMap<UUID, String> savegameWorldsName = new HashMap<>();
|
public static HashMap<UUID, String> savegameWorldsName = new HashMap<>();
|
||||||
|
|
||||||
public static ArrayList<UUID> sortedPlayers = new ArrayList();
|
public static ArrayList<UUID> sortedPlayers = new ArrayList();
|
||||||
public static HashMap<UUID, DiskSkimmer> savegamePlayers = new HashMap<>();
|
public static HashMap<UUID, SavegameCollection> savegamePlayers = new HashMap<>();
|
||||||
public static HashMap<UUID, String> savegamePlayersName = new HashMap<>();
|
public static HashMap<UUID, String> savegamePlayersName = new HashMap<>();
|
||||||
|
|
||||||
public static void updateListOfSavegames() {
|
public static void updateListOfSavegames() {
|
||||||
@@ -346,10 +352,13 @@ public class App implements ApplicationListener {
|
|||||||
processorVendor = "Unknown CPU";
|
processorVendor = "Unknown CPU";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (processor.startsWith("Apple M") && Objects.equals(systemArch, "aarch64")) {
|
if (processor.startsWith("Apple M") && systemArch.equals("aarch64")) {
|
||||||
isAppleM = true;
|
isAppleM = true;
|
||||||
System.out.println("Apple Proprietary "+processor+" detected; don't expect smooth sailing...");
|
System.out.println("Apple Proprietary "+processor+" detected; don't expect smooth sailing...");
|
||||||
}
|
}
|
||||||
|
if (processor.startsWith("Apple M") && !systemArch.equals("aarch64")) {
|
||||||
|
undesirableConditions = "apple_execution_through_rosetta";
|
||||||
|
}
|
||||||
|
|
||||||
if (!IS_DEVELOPMENT_BUILD) {
|
if (!IS_DEVELOPMENT_BUILD) {
|
||||||
var p = UnsafeHelper.INSTANCE.allocate(64);
|
var p = UnsafeHelper.INSTANCE.allocate(64);
|
||||||
@@ -374,8 +383,8 @@ public class App implements ApplicationListener {
|
|||||||
ShaderProgram.pedantic = false;
|
ShaderProgram.pedantic = false;
|
||||||
|
|
||||||
scr = new TerrarumScreenSize(getConfigInt("screenwidth"), getConfigInt("screenheight"));
|
scr = new TerrarumScreenSize(getConfigInt("screenwidth"), getConfigInt("screenheight"));
|
||||||
int width = (int) Math.round(scr.getWidth() * scr.getMagn());
|
int width = scr.getWindowW();
|
||||||
int height = (int) Math.round(scr.getHeight() * scr.getMagn());
|
int height = scr.getWindowH();
|
||||||
|
|
||||||
Lwjgl3ApplicationConfiguration appConfig = new Lwjgl3ApplicationConfiguration();
|
Lwjgl3ApplicationConfiguration appConfig = new Lwjgl3ApplicationConfiguration();
|
||||||
//appConfig.useGL30 = false; // https://stackoverflow.com/questions/46753218/libgdx-should-i-use-gl30
|
//appConfig.useGL30 = false; // https://stackoverflow.com/questions/46753218/libgdx-should-i-use-gl30
|
||||||
@@ -557,7 +566,7 @@ public class App implements ApplicationListener {
|
|||||||
false,
|
false,
|
||||||
64, false, 0.5f, false
|
64, false, 0.5f, false
|
||||||
);
|
);
|
||||||
fontUITitle.setInterchar(2);
|
fontUITitle.setInterchar(1);
|
||||||
fontGameFBO = new TerrarumSansBitmap(FONT_DIR, false, true, false,
|
fontGameFBO = new TerrarumSansBitmap(FONT_DIR, false, true, false,
|
||||||
false,
|
false,
|
||||||
64, false, 203f/255f, false
|
64, false, 203f/255f, false
|
||||||
@@ -631,7 +640,6 @@ public class App implements ApplicationListener {
|
|||||||
// process screenshot request
|
// process screenshot request
|
||||||
if (screenshotRequested) {
|
if (screenshotRequested) {
|
||||||
FrameBufferManager.begin(postProcessorOutFBO);
|
FrameBufferManager.begin(postProcessorOutFBO);
|
||||||
screenshotRequested = false;
|
|
||||||
try {
|
try {
|
||||||
Pixmap p = Pixmap.createFromFrameBuffer(0, 0, scr.getWidth(), scr.getHeight());
|
Pixmap p = Pixmap.createFromFrameBuffer(0, 0, scr.getWidth(), scr.getHeight());
|
||||||
PixmapIO.writePNG(Gdx.files.absolute(defaultDir+"/Screenshot-"+String.valueOf(System.currentTimeMillis())+".png"), p, 9, true);
|
PixmapIO.writePNG(Gdx.files.absolute(defaultDir+"/Screenshot-"+String.valueOf(System.currentTimeMillis())+".png"), p, 9, true);
|
||||||
@@ -643,6 +651,7 @@ public class App implements ApplicationListener {
|
|||||||
Terrarum.INSTANCE.getIngame().sendNotification("Failed to take screenshot: "+e.getMessage());
|
Terrarum.INSTANCE.getIngame().sendNotification("Failed to take screenshot: "+e.getMessage());
|
||||||
}
|
}
|
||||||
FrameBufferManager.end();
|
FrameBufferManager.end();
|
||||||
|
screenshotRequested = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -767,12 +776,9 @@ public class App implements ApplicationListener {
|
|||||||
@Override
|
@Override
|
||||||
public void resize(int w0, int h0) {
|
public void resize(int w0, int h0) {
|
||||||
|
|
||||||
int w = (w0%2==0)?w0:w0+1;
|
|
||||||
int h = (h0%2==0)?h0:h0+1;
|
|
||||||
|
|
||||||
float magn = (float) getConfigDouble("screenmagnifying");
|
float magn = (float) getConfigDouble("screenmagnifying");
|
||||||
int width = Math.round(w / magn);
|
int width = (int) Math.floor(w0 / magn);
|
||||||
int height = Math.round(h / magn);
|
int height = (int) Math.floor(h0 / magn);
|
||||||
|
|
||||||
|
|
||||||
printdbg(this, "Resize called: "+width+","+height);
|
printdbg(this, "Resize called: "+width+","+height);
|
||||||
@@ -782,7 +788,7 @@ public class App implements ApplicationListener {
|
|||||||
|
|
||||||
//initViewPort(width, height);
|
//initViewPort(width, height);
|
||||||
|
|
||||||
scr.setDimension(width, height, magn, w, h);
|
scr.setDimension(width, height, magn);
|
||||||
|
|
||||||
if (currentScreen != null) currentScreen.resize(scr.getWidth(), scr.getHeight());
|
if (currentScreen != null) currentScreen.resize(scr.getWidth(), scr.getHeight());
|
||||||
TerrarumPostProcessor.INSTANCE.resize(scr.getWidth(), scr.getHeight());
|
TerrarumPostProcessor.INSTANCE.resize(scr.getWidth(), scr.getHeight());
|
||||||
@@ -855,7 +861,7 @@ public class App implements ApplicationListener {
|
|||||||
fullscreenQuad.dispose();
|
fullscreenQuad.dispose();
|
||||||
logoBatch.dispose();
|
logoBatch.dispose();
|
||||||
batch.dispose();
|
batch.dispose();
|
||||||
shapeRender.dispose();
|
// shapeRender.dispose();
|
||||||
|
|
||||||
fontGame.dispose();
|
fontGame.dispose();
|
||||||
fontGameFBO.dispose();
|
fontGameFBO.dispose();
|
||||||
@@ -1133,6 +1139,11 @@ public class App implements ApplicationListener {
|
|||||||
|
|
||||||
public static RunningEnvironment environment;
|
public static RunningEnvironment environment;
|
||||||
|
|
||||||
|
/** defaultDir + "/Recycled/Players" */
|
||||||
|
public static String recycledPlayersDir;
|
||||||
|
/** defaultDir + "/Recycled/Worlds" */
|
||||||
|
public static String recycledWorldsDir;
|
||||||
|
|
||||||
private static void getDefaultDirectory() {
|
private static void getDefaultDirectory() {
|
||||||
String OS = OSName.toUpperCase();
|
String OS = OSName.toUpperCase();
|
||||||
if (OS.contains("WIN")) {
|
if (OS.contains("WIN")) {
|
||||||
@@ -1162,6 +1173,8 @@ public class App implements ApplicationListener {
|
|||||||
worldsDir = defaultDir + "/Worlds";
|
worldsDir = defaultDir + "/Worlds";
|
||||||
configDir = defaultDir + "/config.json";
|
configDir = defaultDir + "/config.json";
|
||||||
loadOrderDir = defaultDir + "/LoadOrder.txt";
|
loadOrderDir = defaultDir + "/LoadOrder.txt";
|
||||||
|
recycledPlayersDir = defaultDir + "/Recycled/Players";
|
||||||
|
recycledWorldsDir = defaultDir + "/Recycled/Worlds";
|
||||||
|
|
||||||
System.out.println(String.format("os.name = %s (with identifier %s)", OSName, operationSystem));
|
System.out.println(String.format("os.name = %s (with identifier %s)", OSName, operationSystem));
|
||||||
System.out.println(String.format("os.version = %s", OSVersion));
|
System.out.println(String.format("os.version = %s", OSVersion));
|
||||||
@@ -1171,10 +1184,12 @@ public class App implements ApplicationListener {
|
|||||||
|
|
||||||
private static void createDirs() {
|
private static void createDirs() {
|
||||||
File[] dirs = {
|
File[] dirs = {
|
||||||
new File(saveDir),
|
// new File(saveDir),
|
||||||
new File(saveSharedDir),
|
new File(saveSharedDir),
|
||||||
new File(playersDir),
|
new File(playersDir),
|
||||||
new File(worldsDir)
|
new File(worldsDir),
|
||||||
|
new File(recycledPlayersDir),
|
||||||
|
new File(recycledWorldsDir),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (File it : dirs) {
|
for (File it : dirs) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.torvald.terrarum
|
package net.torvald.terrarum
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx
|
||||||
import net.torvald.unicode.BULLET
|
import net.torvald.unicode.BULLET
|
||||||
import net.torvald.unicode.ENDASH
|
import net.torvald.unicode.ENDASH
|
||||||
|
|
||||||
@@ -223,6 +224,22 @@ Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
|||||||
""").split('\n')
|
""").split('\n')
|
||||||
|
|
||||||
|
|
||||||
|
private val javaVersion = System.getProperty("java.version")
|
||||||
|
private val osName = App.OSName
|
||||||
|
private val osVersion = App.OSVersion
|
||||||
|
private val sysArch = App.systemArch
|
||||||
|
private val processor = App.processor
|
||||||
|
private val processorVendor = App.processorVendor
|
||||||
|
private val glinfo = Gdx.graphics.glVersion.debugVersionString
|
||||||
|
|
||||||
|
val systeminfo: List<String>; get() = """
|
||||||
|
JRE Version: $javaVersion
|
||||||
|
Operation System: $osName $osVersion
|
||||||
|
Architecture: $sysArch
|
||||||
|
Processor: $processor ($processorVendor)
|
||||||
|
GL Info: $glinfo
|
||||||
|
""".split('\n')
|
||||||
|
|
||||||
|
|
||||||
val gpl3: List<String>; get() = """ GNU GENERAL PUBLIC LICENSE
|
val gpl3: List<String>; get() = """ GNU GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 29 June 2007
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ import com.badlogic.gdx.Input
|
|||||||
object DefaultConfig {
|
object DefaultConfig {
|
||||||
|
|
||||||
val hashMap = hashMapOf<String, Any>(
|
val hashMap = hashMapOf<String, Any>(
|
||||||
|
"jvm_xmx" to 4,
|
||||||
|
"jvm_extra_cmd" to "",
|
||||||
|
|
||||||
"displayfps" to 0, // 0: no limit, non-zero: limit
|
"displayfps" to 0, // 0: no limit, non-zero: limit
|
||||||
"displayfpsidle" to 0, // 0: no limit, non-zero: limit
|
"displayfpsidle" to 0, // 0: no limit, non-zero: limit
|
||||||
"displaycolourdepth" to 8,
|
"displaycolourdepth" to 8,
|
||||||
@@ -19,9 +22,9 @@ object DefaultConfig {
|
|||||||
"atlastexsize" to 2048,
|
"atlastexsize" to 2048,
|
||||||
|
|
||||||
"language" to App.getSysLang(),
|
"language" to App.getSysLang(),
|
||||||
"notificationshowuptime" to 4096, // 4s
|
"notificationshowuptime" to 4000, // 4s
|
||||||
"selecteditemnameshowuptime" to 4096, // 4s
|
"selecteditemnameshowuptime" to 4000, // 4s
|
||||||
"autosaveinterval" to 262144, // 4m22s
|
"autosaveinterval" to 300000, // 5s
|
||||||
"multithread" to true,
|
"multithread" to true,
|
||||||
|
|
||||||
"showhealthmessageonstartup" to true,
|
"showhealthmessageonstartup" to true,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
|||||||
import net.torvald.terrarum.gameactors.Actor
|
import net.torvald.terrarum.gameactors.Actor
|
||||||
import net.torvald.terrarum.gameactors.ActorID
|
import net.torvald.terrarum.gameactors.ActorID
|
||||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||||
|
import net.torvald.terrarum.gameactors.ActorWithBody.Companion.PHYS_EPSILON_DIST
|
||||||
import net.torvald.terrarum.gameactors.BlockMarkerActor
|
import net.torvald.terrarum.gameactors.BlockMarkerActor
|
||||||
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
|
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
|
||||||
import net.torvald.terrarum.gameitems.ItemID
|
import net.torvald.terrarum.gameitems.ItemID
|
||||||
@@ -26,6 +27,8 @@ import java.io.File
|
|||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.StandardCopyOption
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.locks.Lock
|
import java.util.concurrent.locks.Lock
|
||||||
import java.util.function.Consumer
|
import java.util.function.Consumer
|
||||||
@@ -49,8 +52,8 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
|||||||
|
|
||||||
override fun getMax(axis: Int, t: ActorWithBody): Double =
|
override fun getMax(axis: Int, t: ActorWithBody): Double =
|
||||||
when (axis) {
|
when (axis) {
|
||||||
0 -> t.hitbox.endX
|
0 -> t.hitbox.endX - PHYS_EPSILON_DIST
|
||||||
1 -> t.hitbox.endY
|
1 -> t.hitbox.endY - PHYS_EPSILON_DIST
|
||||||
else -> throw IllegalArgumentException("nonexistent axis $axis for ${dimensions}-dimensional object")
|
else -> throw IllegalArgumentException("nonexistent axis $axis for ${dimensions}-dimensional object")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -406,6 +409,14 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
|||||||
return uiTooltip.message
|
return uiTooltip.message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun requestForceSave(callback: () -> Unit) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun saveTheGame(onSuccessful: () -> Unit, onError: (Throwable) -> Unit) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies most recent `save` to `save.1`, leaving `save` for overwriting, previous `save.1` will be copied to `save.2`
|
* Copies most recent `save` to `save.1`, leaving `save` for overwriting, previous `save.1` will be copied to `save.2`
|
||||||
*/
|
*/
|
||||||
@@ -422,25 +433,55 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
|||||||
// do not overwrite clean .2 with dirty .1
|
// do not overwrite clean .2 with dirty .1
|
||||||
val flags3 = FileInputStream(file3).let { it.skip(49L); val r = it.read(); it.close(); r }
|
val flags3 = FileInputStream(file3).let { it.skip(49L); val r = it.read(); it.close(); r }
|
||||||
val flags2 = FileInputStream(file2).let { it.skip(49L); val r = it.read(); it.close(); r }
|
val flags2 = FileInputStream(file2).let { it.skip(49L); val r = it.read(); it.close(); r }
|
||||||
if (!(flags3 == 0 && flags2 != 0) || !file3.exists()) file2.copyTo(file3, true)
|
if (!(flags3 == 0 && flags2 != 0) || !file3.exists()) Files.move(file2.toPath(), file3.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
|
||||||
} catch (e: NoSuchFileException) {} catch (e: FileNotFoundException) {}
|
} catch (e: NoSuchFileException) {} catch (e: FileNotFoundException) {}
|
||||||
try {
|
try {
|
||||||
// do not overwrite clean .2 with dirty .1
|
// do not overwrite clean .2 with dirty .1
|
||||||
val flags2 = FileInputStream(file2).let { it.skip(49L); val r = it.read(); it.close(); r }
|
val flags2 = FileInputStream(file2).let { it.skip(49L); val r = it.read(); it.close(); r }
|
||||||
val flags1 = FileInputStream(file1).let { it.skip(49L); val r = it.read(); it.close(); r }
|
val flags1 = FileInputStream(file1).let { it.skip(49L); val r = it.read(); it.close(); r }
|
||||||
if (!(flags2 == 0 && flags1 != 0) || !file2.exists()) file1.copyTo(file2, true)
|
if (!(flags2 == 0 && flags1 != 0) || !file2.exists()) Files.move(file1.toPath(), file2.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
|
||||||
} catch (e: NoSuchFileException) {} catch (e: FileNotFoundException) {}
|
} catch (e: NoSuchFileException) {} catch (e: FileNotFoundException) {}
|
||||||
try {
|
try {
|
||||||
if (file2.exists() && !file3.exists())
|
if (file2.exists() && !file3.exists())
|
||||||
file2.copyTo(file3, true)
|
Files.move(file2.toPath(), file3.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
|
||||||
if (file1.exists() && !file2.exists())
|
if (file1.exists() && !file2.exists())
|
||||||
file1.copyTo(file2, true)
|
Files.move(file1.toPath(), file2.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
|
||||||
file.copyTo(file1, true)
|
file.copyTo(file1, true)
|
||||||
} catch (e: IOException) {}
|
} catch (e: IOException) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun makeSavegameBackupCopyAuto(file0: File): File {
|
||||||
|
val file1 = File("${file0.absolutePath}.a")
|
||||||
|
val file2 = File("${file0.absolutePath}.b")
|
||||||
|
val file3 = File("${file0.absolutePath}.c")
|
||||||
|
|
||||||
|
try {
|
||||||
|
// do not overwrite clean .2 with dirty .1
|
||||||
|
val flags3 = FileInputStream(file3).let { it.skip(49L); val r = it.read(); it.close(); r }
|
||||||
|
val flags2 = FileInputStream(file2).let { it.skip(49L); val r = it.read(); it.close(); r }
|
||||||
|
if (!(flags3 == 0 && flags2 != 0) || !file3.exists()) Files.move(file2.toPath(), file3.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
} catch (e: NoSuchFileException) {} catch (e: FileNotFoundException) {}
|
||||||
|
try {
|
||||||
|
// do not overwrite clean .2 with dirty .1
|
||||||
|
val flags2 = FileInputStream(file2).let { it.skip(49L); val r = it.read(); it.close(); r }
|
||||||
|
val flags1 = FileInputStream(file1).let { it.skip(49L); val r = it.read(); it.close(); r }
|
||||||
|
if (!(flags2 == 0 && flags1 != 0) || !file2.exists()) Files.move(file1.toPath(), file2.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
} catch (e: NoSuchFileException) {} catch (e: FileNotFoundException) {}
|
||||||
|
try {
|
||||||
|
if (file2.exists() && !file3.exists())
|
||||||
|
Files.move(file2.toPath(), file3.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
if (file1.exists() && !file2.exists())
|
||||||
|
Files.move(file1.toPath(), file2.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
|
||||||
|
file0.copyTo(file1, true)
|
||||||
|
} catch (e: IOException) {}
|
||||||
|
|
||||||
|
return file1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// simple euclidean norm, squared
|
// simple euclidean norm, squared
|
||||||
private val actorDistanceCalculator = DistanceCalculator<ActorWithBody> { t: ActorWithBody, p: PointND ->
|
private val actorDistanceCalculator = DistanceCalculator<ActorWithBody> { t: ActorWithBody, p: PointND ->
|
||||||
@@ -449,7 +490,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
|||||||
val dist2 = (p.getOrd(0) - (t.hitbox.centeredX - world.width * TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr()
|
val dist2 = (p.getOrd(0) - (t.hitbox.centeredX - world.width * TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr()
|
||||||
val dist3 = (p.getOrd(0) - (t.hitbox.centeredX + world.width * TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr()
|
val dist3 = (p.getOrd(0) - (t.hitbox.centeredX + world.width * TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr()
|
||||||
|
|
||||||
minOf(dist1, minOf(dist2, dist3))
|
minOf(dist1, dist2, dist3)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -467,7 +508,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
|||||||
fun getActorsAt(worldX: Double, worldY: Double): List<ActorWithBody> {
|
fun getActorsAt(worldX: Double, worldY: Double): List<ActorWithBody> {
|
||||||
val outList = ArrayList<ActorWithBody>()
|
val outList = ArrayList<ActorWithBody>()
|
||||||
try {
|
try {
|
||||||
actorsRTree.find(worldX, worldY, worldX + 1.0, worldY + 1.0, outList)
|
actorsRTree.find(worldX, worldY, worldX, worldY, outList)
|
||||||
}
|
}
|
||||||
catch (e: NullPointerException) {}
|
catch (e: NullPointerException) {}
|
||||||
return outList
|
return outList
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.badlogic.gdx.Gdx
|
|||||||
import com.badlogic.gdx.files.FileHandle
|
import com.badlogic.gdx.files.FileHandle
|
||||||
import com.badlogic.gdx.utils.JsonValue
|
import com.badlogic.gdx.utils.JsonValue
|
||||||
import net.torvald.terrarum.App.*
|
import net.torvald.terrarum.App.*
|
||||||
|
import net.torvald.terrarum.App.setToGameConfig
|
||||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||||
import net.torvald.terrarum.blockproperties.WireCodex
|
import net.torvald.terrarum.blockproperties.WireCodex
|
||||||
import net.torvald.terrarum.gameitems.GameItem
|
import net.torvald.terrarum.gameitems.GameItem
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.torvald.terrarum
|
package net.torvald.terrarum
|
||||||
|
|
||||||
|
import net.torvald.random.XXHash32
|
||||||
import org.dyn4j.geometry.Vector2
|
import org.dyn4j.geometry.Vector2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,6 +116,10 @@ class Point2i() {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int = XXHash32.hashGeoCoord(x, y)
|
||||||
|
|
||||||
|
override fun toString() = "Point2i($x, $y)"
|
||||||
|
|
||||||
operator fun component1() = x
|
operator fun component1() = x
|
||||||
operator fun component2() = y
|
operator fun component2() = y
|
||||||
}
|
}
|
||||||
|
|||||||
334
src/net/torvald/terrarum/Principii.java
Normal file
334
src/net/torvald/terrarum/Principii.java
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
package net.torvald.terrarum;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.utils.JsonValue;
|
||||||
|
import net.torvald.terrarum.utils.JsonFetcher;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrapper that launches the bundled JVM and injects VM configs such as -Xmx
|
||||||
|
*
|
||||||
|
* Created by minjaesong on 2023-06-22.
|
||||||
|
*/
|
||||||
|
public class Principii {
|
||||||
|
|
||||||
|
private static KVHashMap gameConfig = new KVHashMap();
|
||||||
|
|
||||||
|
private static String OSName = System.getProperty("os.name");
|
||||||
|
|
||||||
|
private static String operationSystem;
|
||||||
|
/** %appdata%/Terrarum, without trailing slash */
|
||||||
|
private static String defaultDir;
|
||||||
|
/** defaultDir + "/config.json" */
|
||||||
|
private static String configDir;
|
||||||
|
|
||||||
|
|
||||||
|
public static void getDefaultDirRoot() {
|
||||||
|
String OS = OSName.toUpperCase();
|
||||||
|
if (OS.contains("WIN")) {
|
||||||
|
operationSystem = "WINDOWS";
|
||||||
|
defaultDir = System.getenv("APPDATA") + "/Terrarum";
|
||||||
|
}
|
||||||
|
else if (OS.contains("OS X") || OS.contains("MACOS")) { // OpenJDK for mac will still report "Mac OS X" with version number "10.16", even on Big Sur and beyond
|
||||||
|
operationSystem = "OSX";
|
||||||
|
defaultDir = System.getProperty("user.home") + "/Library/Application Support/Terrarum";
|
||||||
|
}
|
||||||
|
else if (OS.contains("NUX") || OS.contains("NIX") || OS.contains("BSD")) {
|
||||||
|
operationSystem = "LINUX";
|
||||||
|
defaultDir = System.getProperty("user.home") + "/.Terrarum";
|
||||||
|
}
|
||||||
|
else if (OS.contains("SUNOS")) {
|
||||||
|
operationSystem = "SOLARIS";
|
||||||
|
defaultDir = System.getProperty("user.home") + "/.Terrarum";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
operationSystem = "UNKNOWN";
|
||||||
|
defaultDir = System.getProperty("user.home") + "/.Terrarum";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
boolean devMode = false;
|
||||||
|
|
||||||
|
// if -ea flag is set, turn on all the debug prints
|
||||||
|
try {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
catch (AssertionError e) {
|
||||||
|
devMode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String extracmd = devMode ? " -ea" : "";
|
||||||
|
String OS = OSName.toUpperCase();
|
||||||
|
String CPUARCH = System.getProperty("os.arch").toUpperCase();
|
||||||
|
String runtimeRoot;
|
||||||
|
String runtimeArch;
|
||||||
|
if (!CPUARCH.equals("AMD64") && !CPUARCH.equals("X86_64") && !CPUARCH.equals("AARCH64")) { // macOS Rosetta2 reports X86_64
|
||||||
|
System.err.println("Unsupported CPU architecture: " + CPUARCH);
|
||||||
|
System.exit(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
runtimeArch = (CPUARCH.equals("AMD64") || CPUARCH.equals("X86_64")) ? "x86" : "arm";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OS.contains("WIN")) {
|
||||||
|
runtimeRoot = "runtime-windows-" + runtimeArch;
|
||||||
|
}
|
||||||
|
else if (OS.contains("OS X") || OS.contains("MACOS")) { // OpenJDK for mac will still report "Mac OS X" with version number "10.16", even on Big Sur and beyond
|
||||||
|
runtimeRoot = "runtime-osx-" + runtimeArch;
|
||||||
|
extracmd += " -XstartOnFirstThread";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
runtimeRoot = "runtime-linux-" + runtimeArch;
|
||||||
|
extracmd += " -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd";
|
||||||
|
}
|
||||||
|
|
||||||
|
String runtime = new File("out/"+runtimeRoot+"/bin/java").getAbsolutePath();
|
||||||
|
System.out.println("Runtime path: "+runtime);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
getDefaultDirRoot();
|
||||||
|
configDir = defaultDir + "/config.json";
|
||||||
|
|
||||||
|
initialiseConfig();
|
||||||
|
readConfigJson();
|
||||||
|
|
||||||
|
|
||||||
|
int xmx = getConfigInt("jvm_xmx");
|
||||||
|
String userDefinedExtraCmd = getConfigString("jvm_extra_cmd").trim();
|
||||||
|
if (!userDefinedExtraCmd.isEmpty()) userDefinedExtraCmd = " "+userDefinedExtraCmd;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
String[] cmd = (runtime+extracmd+userDefinedExtraCmd+" -Xms1G -Xmx"+xmx+"G -cp ./out/TerrarumBuild.jar net.torvald.terrarum.App").split(" ");
|
||||||
|
ProcessBuilder pb = new ProcessBuilder(cmd);
|
||||||
|
pb.inheritIO();
|
||||||
|
System.exit(pb.start().waitFor());
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// CONFIG //
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return config from config set. If the config does not exist, default value will be returned.
|
||||||
|
* @param key
|
||||||
|
* *
|
||||||
|
* @return Config from config set or default config if it does not exist.
|
||||||
|
* *
|
||||||
|
* @throws NullPointerException if the specified config simply does not exist.
|
||||||
|
*/
|
||||||
|
private static int getConfigInt(String key) {
|
||||||
|
Object cfg = getConfigMaster(key);
|
||||||
|
|
||||||
|
if (cfg instanceof Integer) return ((int) cfg);
|
||||||
|
|
||||||
|
double value = (double) cfg;
|
||||||
|
|
||||||
|
if (Math.abs(value % 1.0) < 0.00000001)
|
||||||
|
return (int) Math.round(value);
|
||||||
|
return ((int) cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return config from config set. If the config does not exist, default value will be returned.
|
||||||
|
* @param key
|
||||||
|
* *
|
||||||
|
* @return Config from config set or default config if it does not exist.
|
||||||
|
* *
|
||||||
|
* @throws NullPointerException if the specified config simply does not exist.
|
||||||
|
*/
|
||||||
|
private static double getConfigDouble(String key) {
|
||||||
|
Object cfg = getConfigMaster(key);
|
||||||
|
return (cfg instanceof Integer) ? (((Integer) cfg) * 1.0) : ((double) (cfg));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return config from config set. If the config does not exist, default value will be returned.
|
||||||
|
* @param key
|
||||||
|
* *
|
||||||
|
* @return Config from config set or default config if it does not exist.
|
||||||
|
* *
|
||||||
|
* @throws NullPointerException if the specified config simply does not exist.
|
||||||
|
*/
|
||||||
|
private static String getConfigString(String key) {
|
||||||
|
Object cfg = getConfigMaster(key);
|
||||||
|
return ((String) cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return config from config set. If the config does not exist, default value will be returned.
|
||||||
|
* @param key
|
||||||
|
* *
|
||||||
|
* @return Config from config set or default config if it does not exist. If the default value is undefined, will return false.
|
||||||
|
*/
|
||||||
|
private static boolean getConfigBoolean(String key) {
|
||||||
|
try {
|
||||||
|
Object cfg = getConfigMaster(key);
|
||||||
|
return ((boolean) cfg);
|
||||||
|
}
|
||||||
|
catch (NullPointerException keyNotFound) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*private static int[] getConfigIntArray(String key) {
|
||||||
|
Object cfg = getConfigMaster(key);
|
||||||
|
if (cfg instanceof JsonArray) {
|
||||||
|
JsonArray jsonArray = ((JsonArray) cfg).getAsJsonArray();
|
||||||
|
//return IntArray(jsonArray.size(), { i -> jsonArray[i].asInt })
|
||||||
|
int[] intArray = new int[jsonArray.size()];
|
||||||
|
for (int i = 0; i < jsonArray.size(); i++) {
|
||||||
|
intArray[i] = jsonArray.get(i).getAsInt();
|
||||||
|
}
|
||||||
|
return intArray;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return ((int[]) cfg);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
private static double[] getConfigDoubleArray(String key) {
|
||||||
|
Object cfg = getConfigMaster(key);
|
||||||
|
return ((double[]) cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[] getConfigIntArray(String key) {
|
||||||
|
double[] a = getConfigDoubleArray(key);
|
||||||
|
int[] r = new int[a.length];
|
||||||
|
for (int i = 0; i < a.length; i++) {
|
||||||
|
r[i] = ((int) a[i]);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*private static String[] getConfigStringArray(String key) {
|
||||||
|
Object cfg = getConfigMaster(key);
|
||||||
|
if (cfg instanceof JsonArray) {
|
||||||
|
JsonArray jsonArray = ((JsonArray) cfg).getAsJsonArray();
|
||||||
|
//return IntArray(jsonArray.size(), { i -> jsonArray[i].asInt })
|
||||||
|
String[] intArray = new String[jsonArray.size()];
|
||||||
|
for (int i = 0; i < jsonArray.size(); i++) {
|
||||||
|
intArray[i] = jsonArray.get(i).getAsString();
|
||||||
|
}
|
||||||
|
return intArray;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return ((String[]) cfg);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get config from config file. If the entry does not exist, get from defaults; if the entry is not in the default, NullPointerException will be thrown
|
||||||
|
*/
|
||||||
|
private static HashMap<String, Object> getDefaultConfig() {
|
||||||
|
return DefaultConfig.INSTANCE.getHashMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object getConfigMaster(String key1) {
|
||||||
|
String key = key1.toLowerCase();
|
||||||
|
|
||||||
|
Object config;
|
||||||
|
try {
|
||||||
|
config = gameConfig.get(key);
|
||||||
|
}
|
||||||
|
catch (NullPointerException e) {
|
||||||
|
config = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object defaults;
|
||||||
|
try {
|
||||||
|
defaults = getDefaultConfig().get(key);
|
||||||
|
}
|
||||||
|
catch (NullPointerException e) {
|
||||||
|
defaults = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config == null) {
|
||||||
|
if (defaults == null) {
|
||||||
|
throw new NullPointerException("key not found: '" + key + "'");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return defaults;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return true on successful, false on failure.
|
||||||
|
*/
|
||||||
|
private static Boolean readConfigJson() {
|
||||||
|
System.out.println("Config file: " + configDir);
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
// read from disk and build config from it
|
||||||
|
JsonValue map = JsonFetcher.INSTANCE.invoke(configDir);
|
||||||
|
|
||||||
|
// make config
|
||||||
|
for (JsonValue entry = map.child; entry != null; entry = entry.next) {
|
||||||
|
setToGameConfigForced(entry, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
// write default config to game dir. Call th.is method again to read config from it.
|
||||||
|
e.printStackTrace();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads DefaultConfig to populate the gameConfig
|
||||||
|
*/
|
||||||
|
private static void initialiseConfig() {
|
||||||
|
for (Map.Entry<String, Object> entry : DefaultConfig.INSTANCE.getHashMap().entrySet()) {
|
||||||
|
gameConfig.set(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will forcibly overwrite previously loaded config value.
|
||||||
|
*
|
||||||
|
* Key naming convention will be 'modName:propertyName'; if modName is null, the key will be just propertyName.
|
||||||
|
*
|
||||||
|
* @param value JsonValue (the key-value pair)
|
||||||
|
* @param modName module name, nullable
|
||||||
|
*/
|
||||||
|
private static void setToGameConfigForced(JsonValue value, String modName) {
|
||||||
|
gameConfig.set((modName == null) ? value.name : modName+":"+value.name,
|
||||||
|
value.isArray() ? value.asDoubleArray() :
|
||||||
|
value.isDouble() ? value.asDouble() :
|
||||||
|
value.isBoolean() ? value.asBoolean() :
|
||||||
|
value.isLong() ? value.asInt() :
|
||||||
|
value.asString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
184
src/net/torvald/terrarum/SavegameCollection.kt
Normal file
184
src/net/torvald/terrarum/SavegameCollection.kt
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
package net.torvald.terrarum
|
||||||
|
|
||||||
|
import net.torvald.terrarum.App.printdbg
|
||||||
|
import net.torvald.terrarum.savegame.DiskSkimmer
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.StandardCopyOption
|
||||||
|
import kotlin.io.path.Path
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2023-06-24.
|
||||||
|
*/
|
||||||
|
class SavegameCollection(files0: List<DiskSkimmer>) {
|
||||||
|
|
||||||
|
/** Sorted in reverse by the last modified time of the files, index zero being the most recent */
|
||||||
|
val files = files0.sortedByDescending {
|
||||||
|
it.getLastModifiedTime().shl(2) or
|
||||||
|
it.diskFile.extension.matches(Regex("^[abc]${'$'}")).toLong(1) or
|
||||||
|
it.diskFile.extension.isBlank().toLong(0)
|
||||||
|
}
|
||||||
|
/** Sorted in reverse by the last modified time of the files, index zero being the most recent */
|
||||||
|
val autoSaves = files.filter { it.diskFile.extension.matches(Regex("[a-z]")) }
|
||||||
|
/** Sorted in reverse by the last modified time of the files, index zero being the most recent */
|
||||||
|
val manualSaves = files.filter { !it.diskFile.extension.matches(Regex("[a-z]")) }
|
||||||
|
|
||||||
|
init {
|
||||||
|
files.forEach { it.rebuild() }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun collectFromBaseFilename(basedir: File, name: String): SavegameCollection {
|
||||||
|
val files = basedir.listFiles().filter { it.name.startsWith(name) }
|
||||||
|
.mapNotNull { try { DiskSkimmer(it, true) } catch (e: Throwable) { null } }
|
||||||
|
return SavegameCollection(files)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the most recent not-corrupted file
|
||||||
|
*/
|
||||||
|
fun loadable(): DiskSkimmer {
|
||||||
|
return files.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun moveToRecycle(basedir: String) {
|
||||||
|
files.forEach {
|
||||||
|
try {
|
||||||
|
Files.move(it.diskFile.toPath(), Path(basedir, it.diskFile.name), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
}
|
||||||
|
catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBaseFile(): DiskSkimmer {
|
||||||
|
return files.first { it.diskFile.extension.isBlank() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SavegameCollectionPair(player: SavegameCollection?, world: SavegameCollection?) {
|
||||||
|
|
||||||
|
private var manualPlayer: DiskSkimmer? = null
|
||||||
|
private var manualWorld: DiskSkimmer? = null
|
||||||
|
private var autoPlayer: DiskSkimmer? = null
|
||||||
|
private var autoWorld: DiskSkimmer? = null
|
||||||
|
|
||||||
|
var status = 0 // 0: none available, 1: loadable manual save is newer than loadable auto; 2: loadable autosave is newer than loadable manual
|
||||||
|
private set
|
||||||
|
|
||||||
|
var newerSaveIsDamaged = false // only when most recent save is corrupted
|
||||||
|
private set
|
||||||
|
|
||||||
|
init {
|
||||||
|
printdbg(this, "init ($player, $world)")
|
||||||
|
|
||||||
|
if (player != null && world != null) {
|
||||||
|
|
||||||
|
printdbg(this, "player files: " + player.files.joinToString { it.diskFile.name })
|
||||||
|
printdbg(this, "world files:" + world.files.joinToString { it.diskFile.name })
|
||||||
|
|
||||||
|
// if a pair of files were saved successfully, they must have identical lastModifiedTime()
|
||||||
|
var pc = 0; val pt = player.files[0].getLastModifiedTime()
|
||||||
|
var wc = 0; val wt = world.files[0].getLastModifiedTime()
|
||||||
|
while (pc < player.files.size && wc < world.files.size) {
|
||||||
|
val pcf = player.files[pc]
|
||||||
|
val pcm = pcf.getLastModifiedTime()
|
||||||
|
val wcf = world.files[wc]
|
||||||
|
val wcm = wcf.getLastModifiedTime()
|
||||||
|
|
||||||
|
printdbg(this, "pc=$pc, wc=$wc, pcm=$pcm, wcm=$wcm")
|
||||||
|
|
||||||
|
if (playerDiskNotDamaged(pcf) && worldDiskNotDamaged(wcf)) {
|
||||||
|
|
||||||
|
printdbg(this, "pcf.autosaved=${pcf.isAutosaved()}, wcf.autosaved=${wcf.isAutosaved()}")
|
||||||
|
|
||||||
|
when (pcf.isAutosaved().toInt(1) or wcf.isAutosaved().toInt()) {
|
||||||
|
3 -> {
|
||||||
|
if (autoPlayer == null && autoWorld == null) {
|
||||||
|
autoPlayer = pcf
|
||||||
|
autoWorld = wcf
|
||||||
|
}
|
||||||
|
pc += 1
|
||||||
|
wc += 1
|
||||||
|
}
|
||||||
|
0 -> {
|
||||||
|
if (manualPlayer == null && manualWorld == null) {
|
||||||
|
manualPlayer = pcf
|
||||||
|
manualWorld = wcf
|
||||||
|
}
|
||||||
|
pc += 1
|
||||||
|
wc += 1
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
if (pcm > wcm)
|
||||||
|
pc += 1
|
||||||
|
else if (pcm == wcm) {
|
||||||
|
pc += 1
|
||||||
|
wc += 1
|
||||||
|
}
|
||||||
|
else
|
||||||
|
wc += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (manualPlayer != null && manualWorld != null && autoPlayer != null && autoWorld != null)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (manualPlayer != null && manualWorld != null && autoPlayer != null && autoWorld != null) {
|
||||||
|
status = if (manualPlayer!!.getLastModifiedTime() > autoPlayer!!.getLastModifiedTime()) 1 else 2
|
||||||
|
}
|
||||||
|
else if (manualPlayer != null && manualWorld != null || autoPlayer != null && autoWorld != null) {
|
||||||
|
status = 1
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
status = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
printdbg(this, "manualPlayer = ${manualPlayer?.diskFile?.path}")
|
||||||
|
printdbg(this, "manualWorld = ${manualWorld?.diskFile?.path}")
|
||||||
|
printdbg(this, "autoPlayer = ${autoPlayer?.diskFile?.path}")
|
||||||
|
printdbg(this, "autoWorld = ${autoWorld?.diskFile?.path}")
|
||||||
|
printdbg(this, "status = $status")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DiskSkimmer.isAutosaved() = this.getSaveMode().and(0b0000_0010) != 0
|
||||||
|
|
||||||
|
private fun playerDiskNotDamaged(disk: DiskSkimmer): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun worldDiskNotDamaged(disk: DiskSkimmer): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun moreRecentAutosaveAvailable() = (status == 2)
|
||||||
|
fun saveAvaliable() = (status > 0)
|
||||||
|
|
||||||
|
fun getManualSave(): DiskPair? {
|
||||||
|
if (status == 0) return null
|
||||||
|
return DiskPair(manualPlayer!!, manualWorld!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAutoSave(): DiskPair? {
|
||||||
|
if (status != 2) return null
|
||||||
|
return DiskPair(autoPlayer!!, autoWorld!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLoadableSave(): DiskPair? {
|
||||||
|
if (status == 0) return null
|
||||||
|
return if (manualPlayer != null && manualWorld != null)
|
||||||
|
DiskPair(manualPlayer!!, manualWorld!!)
|
||||||
|
else
|
||||||
|
DiskPair(autoPlayer!!, autoWorld!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class DiskPair(val player: DiskSkimmer, val world: DiskSkimmer)
|
||||||
@@ -31,6 +31,8 @@ import net.torvald.terrarum.savegame.DiskSkimmer
|
|||||||
import net.torvald.terrarum.savegame.VDFileID.SAVEGAMEINFO
|
import net.torvald.terrarum.savegame.VDFileID.SAVEGAMEINFO
|
||||||
import net.torvald.terrarum.serialise.Common
|
import net.torvald.terrarum.serialise.Common
|
||||||
import net.torvald.terrarum.ui.UICanvas
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
|
import net.torvald.terrarum.utils.JsonFetcher
|
||||||
|
import net.torvald.terrarum.utils.forEachSiblings
|
||||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap
|
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap
|
||||||
import net.torvald.unsafe.UnsafeHelper
|
import net.torvald.unsafe.UnsafeHelper
|
||||||
@@ -62,11 +64,11 @@ object Terrarum : Disposable {
|
|||||||
*/
|
*/
|
||||||
const val PLAYER_REF_ID: Int = 0x91A7E2
|
const val PLAYER_REF_ID: Int = 0x91A7E2
|
||||||
|
|
||||||
inline fun inShapeRenderer(shapeRendererType: ShapeRenderer.ShapeType = ShapeRenderer.ShapeType.Filled, action: (ShapeRenderer) -> Unit) {
|
/*inline fun inShapeRenderer(shapeRendererType: ShapeRenderer.ShapeType = ShapeRenderer.ShapeType.Filled, action: (ShapeRenderer) -> Unit) {
|
||||||
shapeRender.begin(shapeRendererType)
|
shapeRender.begin(shapeRendererType)
|
||||||
action(shapeRender)
|
action(shapeRender)
|
||||||
shapeRender.end()
|
shapeRender.end()
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
|
||||||
var blockCodex = BlockCodex(); internal set
|
var blockCodex = BlockCodex(); internal set
|
||||||
@@ -628,6 +630,7 @@ fun Float.sqrt() = FastMath.sqrt(this)
|
|||||||
fun Int.abs() = this.absoluteValue
|
fun Int.abs() = this.absoluteValue
|
||||||
fun Double.bipolarClamp(limit: Double) = this.coerceIn(-limit, limit)
|
fun Double.bipolarClamp(limit: Double) = this.coerceIn(-limit, limit)
|
||||||
fun Boolean.toInt(shift: Int = 0) = if (this) 1.shl(shift) else 0
|
fun Boolean.toInt(shift: Int = 0) = if (this) 1.shl(shift) else 0
|
||||||
|
fun Boolean.toLong(shift: Int = 0) = if (this) 1L.shl(shift) else 0L
|
||||||
fun Int.bitCount() = java.lang.Integer.bitCount(this)
|
fun Int.bitCount() = java.lang.Integer.bitCount(this)
|
||||||
fun Long.bitCount() = java.lang.Long.bitCount(this)
|
fun Long.bitCount() = java.lang.Long.bitCount(this)
|
||||||
|
|
||||||
@@ -797,15 +800,17 @@ fun AppUpdateListOfSavegames() {
|
|||||||
}
|
}
|
||||||
}.sortedByDescending { it.getLastModifiedTime() }.forEachIndexed { index, it ->
|
}.sortedByDescending { it.getLastModifiedTime() }.forEachIndexed { index, it ->
|
||||||
println("${index+1}.\t${it.diskFile.absolutePath}")
|
println("${index+1}.\t${it.diskFile.absolutePath}")
|
||||||
it.rebuild() // disk skimmer was created without initialisation, so do it now
|
it.rebuild()
|
||||||
|
|
||||||
val jsonFile = it.getFile(SAVEGAMEINFO)!!
|
val jsonFile = it.getFile(SAVEGAMEINFO)!!
|
||||||
val json = JsonReader().parse(ByteArray64Reader(jsonFile.bytes, Common.CHARSET).readText())
|
var worldUUID: UUID? = null
|
||||||
val worldUUID = UUID.fromString(json.getString("worldIndex"))
|
JsonFetcher.readFromJsonString(ByteArray64Reader(jsonFile.bytes, Common.CHARSET)).forEachSiblings { name, value ->
|
||||||
|
if (name == "worldIndex") worldUUID = UUID.fromString(value.asString())
|
||||||
|
}
|
||||||
|
|
||||||
// if multiple valid savegames with same UUID exist, only the most recent one is retained
|
// if multiple valid savegames with same UUID exist, only the most recent one is retained
|
||||||
if (!App.savegameWorlds.contains(worldUUID)) {
|
if (!App.savegameWorlds.contains(worldUUID)) {
|
||||||
App.savegameWorlds[worldUUID] = it
|
App.savegameWorlds[worldUUID] = SavegameCollection.collectFromBaseFilename(File(worldsDir), it.diskFile.name)
|
||||||
App.savegameWorldsName[worldUUID] = it.getDiskName(Common.CHARSET)
|
App.savegameWorldsName[worldUUID] = it.getDiskName(Common.CHARSET)
|
||||||
App.sortedSavegameWorlds.add(worldUUID)
|
App.sortedSavegameWorlds.add(worldUUID)
|
||||||
}
|
}
|
||||||
@@ -827,15 +832,17 @@ fun AppUpdateListOfSavegames() {
|
|||||||
}
|
}
|
||||||
}.sortedByDescending { it.getLastModifiedTime() }.forEachIndexed { index, it ->
|
}.sortedByDescending { it.getLastModifiedTime() }.forEachIndexed { index, it ->
|
||||||
println("${index+1}.\t${it.diskFile.absolutePath}")
|
println("${index+1}.\t${it.diskFile.absolutePath}")
|
||||||
it.rebuild() // disk skimmer was created without initialisation, so do it now
|
it.rebuild()
|
||||||
|
|
||||||
val jsonFile = it.getFile(SAVEGAMEINFO)!!
|
val jsonFile = it.getFile(SAVEGAMEINFO)!!
|
||||||
val json = JsonReader().parse(ByteArray64Reader(jsonFile.bytes, Common.CHARSET).readText())
|
var playerUUID: UUID? = null
|
||||||
val playerUUID = UUID.fromString(json.getString("uuid"))
|
JsonFetcher.readFromJsonString(ByteArray64Reader(jsonFile.bytes, Common.CHARSET)).forEachSiblings { name, value ->
|
||||||
|
if (name == "uuid") playerUUID = UUID.fromString(value.asString())
|
||||||
|
}
|
||||||
|
|
||||||
// if multiple valid savegames with same UUID exist, only the most recent one is retained
|
// if multiple valid savegames with same UUID exist, only the most recent one is retained
|
||||||
if (!App.savegamePlayers.contains(playerUUID)) {
|
if (!App.savegamePlayers.contains(playerUUID)) {
|
||||||
App.savegamePlayers[playerUUID] = it
|
App.savegamePlayers[playerUUID] = SavegameCollection.collectFromBaseFilename(File(playersDir), it.diskFile.name)
|
||||||
App.savegamePlayersName[playerUUID] = it.getDiskName(Common.CHARSET)
|
App.savegamePlayersName[playerUUID] = it.getDiskName(Common.CHARSET)
|
||||||
App.sortedPlayers.add(playerUUID)
|
App.sortedPlayers.add(playerUUID)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
"""
|
"""
|
||||||
const val DEFAULT_LOADORDER_FILE = """# Load Order
|
const val DEFAULT_LOADORDER_FILE = """# Load Order
|
||||||
# Modules are loaded from top to bottom.
|
# Modules are loaded from top to bottom.
|
||||||
# You can disable basegame, but we don't recommend.
|
# Name of the module corresponds with the name of the directory the module is stored in,
|
||||||
|
# typically under:
|
||||||
|
# 1. assets/mods of the installation path (the modules comes with the release of the game)
|
||||||
|
# 2. %APPDATA%/Modules (the modules installed by the user)
|
||||||
|
# where %APPDATA% is:
|
||||||
|
# Windows -- C:\Users\<username>\AppData\Roaming\Terrarum
|
||||||
|
# macOS -- /Users/<username>/Library/Application Support/Terrarum
|
||||||
|
# Linux -- /home/<username>/.Terrarum
|
||||||
|
# Please refrain from removing 'basegame' on the load order -- it may render the game unpalyable.
|
||||||
|
|
||||||
basegame
|
basegame
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -33,14 +33,16 @@ class TerrarumScreenSize(scrw: Int = defaultW, scrh: Int = defaultH) {
|
|||||||
val tvSafeActionWidth: Int; get() = Math.round(width * TV_SAFE_ACTION)
|
val tvSafeActionWidth: Int; get() = Math.round(width * TV_SAFE_ACTION)
|
||||||
val tvSafeActionHeight: Int; get() = Math.round(height * TV_SAFE_ACTION)
|
val tvSafeActionHeight: Int; get() = Math.round(height * TV_SAFE_ACTION)
|
||||||
|
|
||||||
|
/** Apparent window size. `roundToEven(width * magn)` */
|
||||||
var windowW: Int = 0; private set
|
var windowW: Int = 0; private set
|
||||||
|
/** Apparent window size. `roundToEven(height * magn)` */
|
||||||
var windowH: Int = 0; private set
|
var windowH: Int = 0; private set
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setDimension(maxOf(minimumW, scrw), maxOf(minimumH, scrh), App.getConfigDouble("screenmagnifying").toFloat(), maxOf(minimumW, scrw), maxOf(minimumH, scrh))
|
setDimension(maxOf(minimumW, scrw), maxOf(minimumH, scrh), App.getConfigDouble("screenmagnifying").toFloat())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setDimension(scrw: Int, scrh: Int, magn: Float, ww: Int, wh: Int) {
|
fun setDimension(scrw: Int, scrh: Int, magn: Float,) {
|
||||||
width = scrw and 0x7FFFFFFE
|
width = scrw and 0x7FFFFFFE
|
||||||
height = scrh and 0x7FFFFFFE
|
height = scrh and 0x7FFFFFFE
|
||||||
wf = scrw.toFloat()
|
wf = scrw.toFloat()
|
||||||
@@ -54,11 +56,11 @@ class TerrarumScreenSize(scrw: Int = defaultW, scrh: Int = defaultH) {
|
|||||||
|
|
||||||
this.magn = magn
|
this.magn = magn
|
||||||
|
|
||||||
windowW = ww
|
windowW = (scrw * magn).ceilInt() and 0x7FFFFFFE
|
||||||
windowH = wh
|
windowH = (scrh * magn).ceilInt() and 0x7FFFFFFE
|
||||||
|
|
||||||
|
|
||||||
printdbg(this, "Window dim: $ww x $wh, called by:")
|
printdbg(this, "Window dim: $windowW x $windowH, called by:")
|
||||||
printStackTrace(this)
|
printStackTrace(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -151,4 +151,8 @@ class WireCodex {
|
|||||||
|
|
||||||
printdbg(this, "Setting prop ${prop.id} ->>\t${prop.nameKey}")
|
printdbg(this, "Setting prop ${prop.id} ->>\t${prop.nameKey}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getAllWiresThatAccepts(accept: String): List<Pair<ItemID, WireProp>> {
|
||||||
|
return wireProps.filter { it.value.accepts == accept }.toList()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@ object ScreencapNogui: ConsoleCommand {
|
|||||||
PixmapIO2.writeTGA(Gdx.files.absolute(App.defaultDir + "/Exports/${args[1]}.tga"), p, true)
|
PixmapIO2.writeTGA(Gdx.files.absolute(App.defaultDir + "/Exports/${args[1]}.tga"), p, true)
|
||||||
p.dispose()
|
p.dispose()
|
||||||
}
|
}
|
||||||
IngameRenderer.screencapRequested = true
|
IngameRenderer.requestScreencap()
|
||||||
Echo("FBO exported to$ccG Exports/${args[1]}.tga")
|
Echo("FBO exported to$ccG Exports/${args[1]}.tga")
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -13,10 +13,20 @@ import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
|||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used as construction markers and fixture ghost images
|
* Used as construction markers and fixture ghost images.
|
||||||
|
*
|
||||||
|
* `isVisible` behaves differently by `markerMode`.
|
||||||
|
* - FIXTURE_GHOST: `isVisible` toggles if the ghost is being updated. FALSE - will not be updated and also not visible
|
||||||
|
* - BLOCK_MARKER: `isVisible` controls the visibility. FALSE - invisible, TRUE - always visible
|
||||||
|
*
|
||||||
|
* MarkerMode must be set manually after calling `setGhost` -- the `unsetGhost` will not reset the field.
|
||||||
*/
|
*/
|
||||||
class BlockMarkerActor : ActorWithBody(Actor.RenderOrder.OVERLAY, physProp = PhysProperties.MOBILE_OBJECT), NoSerialise {
|
class BlockMarkerActor : ActorWithBody(Actor.RenderOrder.OVERLAY, physProp = PhysProperties.MOBILE_OBJECT), NoSerialise {
|
||||||
|
|
||||||
|
enum class MarkerMode {
|
||||||
|
FIXTURE_GHOST, BLOCK_MARKER
|
||||||
|
}
|
||||||
|
|
||||||
private val defaultSize = 16.0
|
private val defaultSize = 16.0
|
||||||
|
|
||||||
override var referenceID: ActorID = 2147483647 // custom refID
|
override var referenceID: ActorID = 2147483647 // custom refID
|
||||||
@@ -29,7 +39,7 @@ class BlockMarkerActor : ActorWithBody(Actor.RenderOrder.OVERLAY, physProp = Phy
|
|||||||
get() = CommonResourcePool.getAsTextureRegionPack("blockmarkings_common")
|
get() = CommonResourcePool.getAsTextureRegionPack("blockmarkings_common")
|
||||||
|
|
||||||
private var ghost: SpriteAnimation? = null
|
private var ghost: SpriteAnimation? = null
|
||||||
private var hasGhost = false
|
var markerMode: MarkerMode = MarkerMode.FIXTURE_GHOST
|
||||||
var ghostColour = Color.WHITE
|
var ghostColour = Color.WHITE
|
||||||
|
|
||||||
|
|
||||||
@@ -38,9 +48,10 @@ class BlockMarkerActor : ActorWithBody(Actor.RenderOrder.OVERLAY, physProp = Phy
|
|||||||
renderOrder = Actor.RenderOrder.OVERLAY // for some reason the constructor didn't work
|
renderOrder = Actor.RenderOrder.OVERLAY // for some reason the constructor didn't work
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun drawBody(batch: SpriteBatch) {
|
override fun drawBody(batch: SpriteBatch) {
|
||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
if (hasGhost) {
|
if (markerMode == MarkerMode.FIXTURE_GHOST) {
|
||||||
if (INGAME.actorNowPlaying != null) {
|
if (INGAME.actorNowPlaying != null) {
|
||||||
mouseInInteractableRange(INGAME.actorNowPlaying!!) {
|
mouseInInteractableRange(INGAME.actorNowPlaying!!) {
|
||||||
batch.shader = App.shaderGhastlyWhite
|
batch.shader = App.shaderGhastlyWhite
|
||||||
@@ -59,7 +70,7 @@ class BlockMarkerActor : ActorWithBody(Actor.RenderOrder.OVERLAY, physProp = Phy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else if (markerMode == MarkerMode.BLOCK_MARKER) {
|
||||||
batch.shader = null
|
batch.shader = null
|
||||||
batch.color = markerColour
|
batch.color = markerColour
|
||||||
batch.draw(blockMarkings.get(markerShape, 0), hitbox.startX.toFloat(), hitbox.startY.toFloat())
|
batch.draw(blockMarkings.get(markerShape, 0), hitbox.startX.toFloat(), hitbox.startY.toFloat())
|
||||||
@@ -91,13 +102,12 @@ class BlockMarkerActor : ActorWithBody(Actor.RenderOrder.OVERLAY, physProp = Phy
|
|||||||
|
|
||||||
fun setGhost(actor: ActorWithBody) {
|
fun setGhost(actor: ActorWithBody) {
|
||||||
ghost = actor.sprite
|
ghost = actor.sprite
|
||||||
hasGhost = true
|
markerMode = MarkerMode.FIXTURE_GHOST
|
||||||
hitbox.setDimension(actor.baseHitboxW.toDouble(), actor.baseHitboxH.toDouble())
|
hitbox.setDimension(actor.baseHitboxW.toDouble(), actor.baseHitboxH.toDouble())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun unsetGhost() {
|
fun unsetGhost() {
|
||||||
ghost = null
|
ghost = null
|
||||||
hasGhost = false
|
|
||||||
setGhostColourNone()
|
setGhostColourNone()
|
||||||
hitbox.setDimension(TILE_SIZED, TILE_SIZED)
|
hitbox.setDimension(TILE_SIZED, TILE_SIZED)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,12 @@ class SimpleGameWorld : GameWorld() {
|
|||||||
override lateinit var layerTerrain: BlockLayer
|
override lateinit var layerTerrain: BlockLayer
|
||||||
}
|
}
|
||||||
|
|
||||||
open class GameWorld() : Disposable {
|
open class GameWorld(
|
||||||
|
val worldIndex: UUID // should not be immutable as JSON loader will want to overwrite it
|
||||||
|
) : Disposable {
|
||||||
|
|
||||||
|
constructor() : this(UUID.randomUUID())
|
||||||
|
|
||||||
// var worldName: String = "New World"
|
|
||||||
var worldIndex: UUID = UUID.randomUUID() // should not be immutable as JSON loader will want to overwrite it
|
|
||||||
var worldCreator: UUID = UUID(0L,0L) // TODO record a value to this
|
var worldCreator: UUID = UUID(0L,0L) // TODO record a value to this
|
||||||
var width: Int = 999; private set
|
var width: Int = 999; private set
|
||||||
var height: Int = 999; private set
|
var height: Int = 999; private set
|
||||||
@@ -387,14 +389,14 @@ open class GameWorld() : Disposable {
|
|||||||
return wiringGraph[blockAddr]?.get(itemID)?.emt
|
return wiringGraph[blockAddr]?.get(itemID)?.emt
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getWireRecvStateOf(x: Int, y: Int, itemID: ItemID): ArrayList<WireRecvState>? {
|
fun getWireReceptionStateOf(x: Int, y: Int, itemID: ItemID): ArrayList<WireReceptionState>? {
|
||||||
val (x, y) = coerceXY(x, y)
|
val (x, y) = coerceXY(x, y)
|
||||||
val blockAddr = LandUtil.getBlockAddr(this, x, y)
|
val blockAddr = LandUtil.getBlockAddr(this, x, y)
|
||||||
return getWireRecvStateUnsafe(blockAddr, itemID)
|
return getWireReceptionStateUnsafe(blockAddr, itemID)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getWireRecvStateUnsafe(blockAddr: BlockAddress, itemID: ItemID): ArrayList<WireRecvState>? {
|
fun getWireReceptionStateUnsafe(blockAddr: BlockAddress, itemID: ItemID): ArrayList<WireReceptionState>? {
|
||||||
return wiringGraph[blockAddr]?.get(itemID)?.rcv
|
return wiringGraph[blockAddr]?.get(itemID)?.rcp
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setWireGraphOf(x: Int, y: Int, itemID: ItemID, cnx: Int) {
|
fun setWireGraphOf(x: Int, y: Int, itemID: ItemID, cnx: Int) {
|
||||||
@@ -427,7 +429,7 @@ open class GameWorld() : Disposable {
|
|||||||
wiringGraph[blockAddr]!![itemID]!!.emt.set(vector)
|
wiringGraph[blockAddr]!![itemID]!!.emt.set(vector)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addWireRecvStateOf(x: Int, y: Int, itemID: ItemID, state: WireRecvState) {
|
fun addWireRecvStateOf(x: Int, y: Int, itemID: ItemID, state: WireReceptionState) {
|
||||||
val (x, y) = coerceXY(x, y)
|
val (x, y) = coerceXY(x, y)
|
||||||
val blockAddr = LandUtil.getBlockAddr(this, x, y)
|
val blockAddr = LandUtil.getBlockAddr(this, x, y)
|
||||||
return addWireRecvStateOfUnsafe(blockAddr, itemID, state)
|
return addWireRecvStateOfUnsafe(blockAddr, itemID, state)
|
||||||
@@ -439,13 +441,13 @@ open class GameWorld() : Disposable {
|
|||||||
return clearAllWireRecvStateUnsafe(blockAddr)
|
return clearAllWireRecvStateUnsafe(blockAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addWireRecvStateOfUnsafe(blockAddr: BlockAddress, itemID: ItemID, state: WireRecvState) {
|
fun addWireRecvStateOfUnsafe(blockAddr: BlockAddress, itemID: ItemID, state: WireReceptionState) {
|
||||||
if (wiringGraph[blockAddr] == null)
|
if (wiringGraph[blockAddr] == null)
|
||||||
wiringGraph[blockAddr] = WiringGraphMap()
|
wiringGraph[blockAddr] = WiringGraphMap()
|
||||||
if (wiringGraph[blockAddr]!![itemID] == null)
|
if (wiringGraph[blockAddr]!![itemID] == null)
|
||||||
wiringGraph[blockAddr]!![itemID] = WiringSimCell(0)
|
wiringGraph[blockAddr]!![itemID] = WiringSimCell(0)
|
||||||
|
|
||||||
wiringGraph[blockAddr]!![itemID]!!.rcv.add(state)
|
wiringGraph[blockAddr]!![itemID]!!.rcp.add(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAllWiringGraph(x: Int, y: Int): HashMap<ItemID, WiringSimCell>? {
|
fun getAllWiringGraph(x: Int, y: Int): HashMap<ItemID, WiringSimCell>? {
|
||||||
@@ -460,7 +462,7 @@ open class GameWorld() : Disposable {
|
|||||||
|
|
||||||
fun clearAllWireRecvStateUnsafe(blockAddr: BlockAddress) {
|
fun clearAllWireRecvStateUnsafe(blockAddr: BlockAddress) {
|
||||||
wiringGraph[blockAddr]?.forEach {
|
wiringGraph[blockAddr]?.forEach {
|
||||||
it.value.rcv.clear()
|
it.value.rcp.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -652,7 +654,7 @@ open class GameWorld() : Disposable {
|
|||||||
val ws: SortedArrayList<ItemID> = SortedArrayList<ItemID>() // what could possibly go wrong bloating up the RAM footprint when it's practically infinite these days?
|
val ws: SortedArrayList<ItemID> = SortedArrayList<ItemID>() // what could possibly go wrong bloating up the RAM footprint when it's practically infinite these days?
|
||||||
)
|
)
|
||||||
|
|
||||||
data class WireRecvState(
|
data class WireReceptionState(
|
||||||
var dist: Int = -1, // how many tiles it took to traverse
|
var dist: Int = -1, // how many tiles it took to traverse
|
||||||
var src: Point2i = Point2i(0,0) // xy position
|
var src: Point2i = Point2i(0,0) // xy position
|
||||||
// to get the state, use the src to get the state of the source emitter directly, then use dist to apply attenuation
|
// to get the state, use the src to get the state of the source emitter directly, then use dist to apply attenuation
|
||||||
@@ -664,7 +666,7 @@ open class GameWorld() : Disposable {
|
|||||||
data class WiringSimCell(
|
data class WiringSimCell(
|
||||||
var cnx: Int = 0, // connections. [1, 2, 4, 8] = [RIGHT, DOWN, LEFT, UP]
|
var cnx: Int = 0, // connections. [1, 2, 4, 8] = [RIGHT, DOWN, LEFT, UP]
|
||||||
val emt: Vector2 = Vector2(0.0, 0.0), // i'm emitting this much power
|
val emt: Vector2 = Vector2(0.0, 0.0), // i'm emitting this much power
|
||||||
val rcv: ArrayList<WireRecvState> = ArrayList() // how far away are the power sources
|
val rcp: ArrayList<WireReceptionState> = ArrayList() // how far away are the power sources
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getTemperature(worldTileX: Int, worldTileY: Int): Float? {
|
fun getTemperature(worldTileX: Int, worldTileY: Int): Float? {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package net.torvald.terrarum.gameworld
|
|||||||
import com.badlogic.gdx.utils.Queue
|
import com.badlogic.gdx.utils.Queue
|
||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||||
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
|
||||||
import net.torvald.terrarum.blockproperties.Block
|
import net.torvald.terrarum.blockproperties.Block
|
||||||
import net.torvald.terrarum.blockproperties.Fluid
|
import net.torvald.terrarum.blockproperties.Fluid
|
||||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||||
@@ -468,14 +469,15 @@ object WorldSimulator {
|
|||||||
/**
|
/**
|
||||||
* @return List of FixtureBases, safe to cast into Electric
|
* @return List of FixtureBases, safe to cast into Electric
|
||||||
*/
|
*/
|
||||||
private fun wiresimGetSourceBlocks(): List<FixtureBase> =
|
private fun wiresimGetSourceBlocks(): List<Electric> =
|
||||||
INGAME.actorContainerActive.filterIsInstance<FixtureBase>().filter {
|
INGAME.actorContainerActive.filterIsInstance<Electric>().filter {
|
||||||
it is Electric && it.inUpdateRange(world) && it.wireEmitterTypes.isNotEmpty()
|
it.inUpdateRange(world) && it.wireEmitterTypes.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val wireSimMarked = HashSet<Long>()
|
private val wireSimMarked = HashSet<Long>()
|
||||||
private val wireSimPoints = Queue<WireGraphCursor>()
|
private val wireSimPoints = Queue<WireGraphCursor>()
|
||||||
private val oldTraversedNodes = ArrayList<WireGraphCursor>()
|
private val oldTraversedNodes = ArrayList<WireGraphCursor>()
|
||||||
|
private val fixtureCache = HashMap<Point2i, Pair<Electric, WireEmissionType>>() // also instance of Electric
|
||||||
|
|
||||||
private fun simulateWires(delta: Float) {
|
private fun simulateWires(delta: Float) {
|
||||||
// unset old wires before we begin
|
// unset old wires before we begin
|
||||||
@@ -484,14 +486,15 @@ object WorldSimulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
oldTraversedNodes.clear()
|
oldTraversedNodes.clear()
|
||||||
|
fixtureCache.clear()
|
||||||
|
|
||||||
wiresimGetSourceBlocks().let { sources ->
|
wiresimGetSourceBlocks().let { sources ->
|
||||||
// signal-emitting fixtures must set emitState of its own tiles via update()
|
// signal-emitting fixtures must set emitState of its own tiles via update()
|
||||||
sources.forEach {
|
sources.forEach {
|
||||||
(it as Electric).wireEmitterTypes.forEach { wireType, bbi ->
|
it.wireEmitterTypes.forEach { bbi, wireType ->
|
||||||
|
|
||||||
val startingPoint = it.worldBlockPos!! + it.blockBoxIndexToPoint2i(bbi)
|
val startingPoint = it.worldBlockPos!! + it.blockBoxIndexToPoint2i(bbi)
|
||||||
val signal = (it as Electric).wireEmission[bbi] ?: Vector2(0.0, 0.0)
|
val signal = it.wireEmission[bbi] ?: Vector2(0.0, 0.0)
|
||||||
|
|
||||||
world.getAllWiringGraph(startingPoint.x, startingPoint.y)?.keys?.filter { WireCodex[it].accepts == wireType }?.forEach { wire ->
|
world.getAllWiringGraph(startingPoint.x, startingPoint.y)?.keys?.filter { WireCodex[it].accepts == wireType }?.forEach { wire ->
|
||||||
val simStartingPoint = WireGraphCursor(startingPoint, wire)
|
val simStartingPoint = WireGraphCursor(startingPoint, wire)
|
||||||
@@ -506,6 +509,8 @@ object WorldSimulator {
|
|||||||
|
|
||||||
private fun traverseWireGraph(world: GameWorld, wire: ItemID, startingPoint: WireGraphCursor, signal: Vector2) {
|
private fun traverseWireGraph(world: GameWorld, wire: ItemID, startingPoint: WireGraphCursor, signal: Vector2) {
|
||||||
|
|
||||||
|
val emissionType = WireCodex[wire].accepts
|
||||||
|
|
||||||
fun getAdjacent(cnx: Int, point: WireGraphCursor): List<WireGraphCursor> {
|
fun getAdjacent(cnx: Int, point: WireGraphCursor): List<WireGraphCursor> {
|
||||||
val r = ArrayList<WireGraphCursor>()
|
val r = ArrayList<WireGraphCursor>()
|
||||||
for (dir in intArrayOf(RIGHT, DOWN, LEFT, UP)) {
|
for (dir in intArrayOf(RIGHT, DOWN, LEFT, UP)) {
|
||||||
@@ -540,6 +545,28 @@ object WorldSimulator {
|
|||||||
enq(x)
|
enq(x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// do something with the power receiver
|
||||||
|
val tilePoint = Point2i(point.x, point.y)
|
||||||
|
var fixture = fixtureCache[tilePoint]
|
||||||
|
var tileOffsetFromFixture: Point2i? = null
|
||||||
|
if (fixture == null) {
|
||||||
|
INGAME.getActorsAt(point.x * TILE_SIZED, point.y * TILE_SIZED).filterIsInstance<Electric>().firstOrNull().let { found ->
|
||||||
|
if (found != null) {
|
||||||
|
// get offset from the fixture's origin
|
||||||
|
tileOffsetFromFixture = found.intTilewiseHitbox.let { Point2i(it.startX.toInt(), it.startY.toInt()) } - tilePoint
|
||||||
|
|
||||||
|
// println("$tilePoint; ${found.javaClass.canonicalName}, $tileOffsetFromFixture, ${found.getWireSinkAt(tileOffsetFromFixture!!)}")
|
||||||
|
|
||||||
|
if (found.getWireSinkAt(tileOffsetFromFixture!!) == emissionType) {
|
||||||
|
fixtureCache[tilePoint] = found to emissionType
|
||||||
|
fixture = found to emissionType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fixture?.first?.updateOnWireGraphTraversal(tileOffsetFromFixture!!.x, tileOffsetFromFixture!!.y, fixture!!.second)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import com.badlogic.gdx.utils.Disposable
|
|||||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||||
import net.torvald.random.HQRNG
|
import net.torvald.random.HQRNG
|
||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
import net.torvald.terrarum.App.measureDebugTime
|
import net.torvald.terrarum.App.*
|
||||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF
|
||||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||||
@@ -21,6 +21,7 @@ import net.torvald.terrarum.gameworld.GameWorld
|
|||||||
import net.torvald.terrarum.gameworld.fmod
|
import net.torvald.terrarum.gameworld.fmod
|
||||||
import net.torvald.terrarum.ui.Toolkit
|
import net.torvald.terrarum.ui.Toolkit
|
||||||
import net.torvald.terrarum.weather.WeatherMixer
|
import net.torvald.terrarum.weather.WeatherMixer
|
||||||
|
import net.torvald.terrarum.weather.WeatherMixer.render
|
||||||
import net.torvald.terrarum.worlddrawer.BlocksDrawer
|
import net.torvald.terrarum.worlddrawer.BlocksDrawer
|
||||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
||||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
||||||
@@ -204,7 +205,7 @@ object IngameRenderer : Disposable {
|
|||||||
actorsRenderOverlay: List<ActorWithBody>,
|
actorsRenderOverlay: List<ActorWithBody>,
|
||||||
particlesContainer : CircularArray<ParticleBase>,
|
particlesContainer : CircularArray<ParticleBase>,
|
||||||
player: ActorWithBody? = null,
|
player: ActorWithBody? = null,
|
||||||
uiContainer: UIContainer? = null
|
uiContainer: UIContainer? = null,
|
||||||
) {
|
) {
|
||||||
renderingActorsCount = (actorsRenderBehind.size) +
|
renderingActorsCount = (actorsRenderBehind.size) +
|
||||||
(actorsRenderMiddle.size) +
|
(actorsRenderMiddle.size) +
|
||||||
@@ -365,13 +366,19 @@ object IngameRenderer : Disposable {
|
|||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
if (screencapRequested) {
|
if (screencapRequested) {
|
||||||
screencapRequested = false
|
printdbg(this, "Screencap was requested, processing...")
|
||||||
|
var hasError = false
|
||||||
try {
|
try {
|
||||||
screencapExportCallback(fboMixedOut)
|
screencapExportCallback(fboMixedOut)
|
||||||
}
|
}
|
||||||
catch (e: Throwable) {
|
catch (e: Throwable) {
|
||||||
|
printdbgerr(this, "An error occured while taking screencap:")
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
hasError = true
|
||||||
}
|
}
|
||||||
|
printdbg(this, "Screencap ${if (hasError) "failed" else "successful"}")
|
||||||
|
screencapBusy = false
|
||||||
|
screencapRequested = false
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
@@ -416,11 +423,18 @@ object IngameRenderer : Disposable {
|
|||||||
* This "screencap" will capture the game WITHOUT gui and postprocessors!
|
* This "screencap" will capture the game WITHOUT gui and postprocessors!
|
||||||
* To capture the entire game, use [App.requestScreenshot]
|
* To capture the entire game, use [App.requestScreenshot]
|
||||||
*/
|
*/
|
||||||
@Volatile internal var screencapRequested = false
|
@Volatile private var screencapRequested = false
|
||||||
@Volatile internal var fboRGBexportedLatch = false
|
@Volatile internal var screencapBusy = false; private set
|
||||||
@Volatile internal var screencapExportCallback: (FrameBuffer) -> Unit = {}
|
@Volatile internal var screencapExportCallback: (FrameBuffer) -> Unit = {}
|
||||||
@Volatile internal lateinit var fboRGBexport: Pixmap
|
@Volatile internal lateinit var fboRGBexport: Pixmap
|
||||||
|
|
||||||
|
fun requestScreencap() {
|
||||||
|
screencapRequested = true
|
||||||
|
screencapBusy = true
|
||||||
|
printdbg(this, "requestScreencap called from:")
|
||||||
|
printStackTrace(this)
|
||||||
|
}
|
||||||
|
|
||||||
private fun drawToRGB(
|
private fun drawToRGB(
|
||||||
actorsRenderBehind: List<ActorWithBody>?,
|
actorsRenderBehind: List<ActorWithBody>?,
|
||||||
actorsRenderMiddle: List<ActorWithBody>?,
|
actorsRenderMiddle: List<ActorWithBody>?,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package net.torvald.terrarum.modulebasegame
|
|||||||
import com.badlogic.gdx.Gdx
|
import com.badlogic.gdx.Gdx
|
||||||
import com.badlogic.gdx.Input
|
import com.badlogic.gdx.Input
|
||||||
import com.badlogic.gdx.graphics.Camera
|
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.SpriteBatch
|
||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
import net.torvald.terrarum.App.*
|
import net.torvald.terrarum.App.*
|
||||||
@@ -26,6 +27,7 @@ import net.torvald.terrarum.gameitems.mouseInInteractableRange
|
|||||||
import net.torvald.terrarum.gameparticles.ParticleBase
|
import net.torvald.terrarum.gameparticles.ParticleBase
|
||||||
import net.torvald.terrarum.gameworld.GameWorld
|
import net.torvald.terrarum.gameworld.GameWorld
|
||||||
import net.torvald.terrarum.gameworld.WorldSimulator
|
import net.torvald.terrarum.gameworld.WorldSimulator
|
||||||
|
import net.torvald.terrarum.langpack.Lang
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.*
|
import net.torvald.terrarum.modulebasegame.gameactors.*
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.physicssolver.CollisionSolver
|
import net.torvald.terrarum.modulebasegame.gameactors.physicssolver.CollisionSolver
|
||||||
import net.torvald.terrarum.modulebasegame.gameitems.PickaxeCore
|
import net.torvald.terrarum.modulebasegame.gameitems.PickaxeCore
|
||||||
@@ -34,6 +36,7 @@ import net.torvald.terrarum.modulebasegame.serialise.LoadSavegame
|
|||||||
import net.torvald.terrarum.modulebasegame.serialise.ReadActor
|
import net.torvald.terrarum.modulebasegame.serialise.ReadActor
|
||||||
import net.torvald.terrarum.modulebasegame.serialise.WriteSavegame
|
import net.torvald.terrarum.modulebasegame.serialise.WriteSavegame
|
||||||
import net.torvald.terrarum.modulebasegame.ui.*
|
import net.torvald.terrarum.modulebasegame.ui.*
|
||||||
|
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.gradEndCol
|
||||||
import net.torvald.terrarum.modulebasegame.worldgenerator.RoguelikeRandomiser
|
import net.torvald.terrarum.modulebasegame.worldgenerator.RoguelikeRandomiser
|
||||||
import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen
|
import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen
|
||||||
import net.torvald.terrarum.modulebasegame.worldgenerator.WorldgenParams
|
import net.torvald.terrarum.modulebasegame.worldgenerator.WorldgenParams
|
||||||
@@ -42,6 +45,7 @@ import net.torvald.terrarum.savegame.VDUtil
|
|||||||
import net.torvald.terrarum.savegame.VirtualDisk
|
import net.torvald.terrarum.savegame.VirtualDisk
|
||||||
import net.torvald.terrarum.serialise.Common
|
import net.torvald.terrarum.serialise.Common
|
||||||
import net.torvald.terrarum.ui.Toolkit
|
import net.torvald.terrarum.ui.Toolkit
|
||||||
|
import net.torvald.terrarum.ui.Toolkit.hdrawWidth
|
||||||
import net.torvald.terrarum.ui.UIAutosaveNotifier
|
import net.torvald.terrarum.ui.UIAutosaveNotifier
|
||||||
import net.torvald.terrarum.ui.UICanvas
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
import net.torvald.terrarum.weather.WeatherMixer
|
import net.torvald.terrarum.weather.WeatherMixer
|
||||||
@@ -53,6 +57,7 @@ import net.torvald.unicode.EMDASH
|
|||||||
import net.torvald.util.CircularArray
|
import net.torvald.util.CircularArray
|
||||||
import org.khelekore.prtree.PRTree
|
import org.khelekore.prtree.PRTree
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -260,7 +265,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IngameRenderer.setRenderedWorld(world)
|
IngameRenderer.setRenderedWorld(world)
|
||||||
|
blockMarkingActor.isVisible = true
|
||||||
|
|
||||||
super.show() // this function sets gameInitialised = true
|
super.show() // this function sets gameInitialised = true
|
||||||
}
|
}
|
||||||
@@ -418,10 +423,15 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
// 2. cannot sync up the "counter" to determine whether both are finished
|
// 2. cannot sync up the "counter" to determine whether both are finished
|
||||||
uiAutosaveNotifier.setAsOpen()
|
uiAutosaveNotifier.setAsOpen()
|
||||||
val saveTime_t = App.getTIME_T()
|
val saveTime_t = App.getTIME_T()
|
||||||
|
printdbg(this, "Immediate Save")
|
||||||
WriteSavegame.immediate(saveTime_t, WriteSavegame.SaveMode.PLAYER, playerDisk, getPlayerSaveFiledesc(playerSavefileName), this, true, autosaveOnErrorAction) {
|
WriteSavegame.immediate(saveTime_t, WriteSavegame.SaveMode.PLAYER, playerDisk, getPlayerSaveFiledesc(playerSavefileName), this, true, autosaveOnErrorAction) {
|
||||||
|
printdbg(this, "immediate save callback from PLAYER")
|
||||||
|
|
||||||
makeSavegameBackupCopy(getPlayerSaveFiledesc(playerSavefileName))
|
makeSavegameBackupCopy(getPlayerSaveFiledesc(playerSavefileName))
|
||||||
|
|
||||||
WriteSavegame.immediate(saveTime_t, WriteSavegame.SaveMode.WORLD, worldDisk, getWorldSaveFiledesc(worldSavefileName), this, true, autosaveOnErrorAction) {
|
WriteSavegame.immediate(saveTime_t, WriteSavegame.SaveMode.WORLD, worldDisk, getWorldSaveFiledesc(worldSavefileName), this, true, autosaveOnErrorAction) {
|
||||||
|
printdbg(this, "immediate save callback from WORLD")
|
||||||
|
|
||||||
makeSavegameBackupCopy(getWorldSaveFiledesc(worldSavefileName)) // don't put it on the postInit() or render(); must be called using callback
|
makeSavegameBackupCopy(getWorldSaveFiledesc(worldSavefileName)) // don't put it on the postInit() or render(); must be called using callback
|
||||||
uiAutosaveNotifier.setAsClose()
|
uiAutosaveNotifier.setAsClose()
|
||||||
}
|
}
|
||||||
@@ -470,13 +480,14 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
|
|
||||||
world.worldCreator = UUID.fromString(player.uuid.toString())
|
world.worldCreator = UUID.fromString(player.uuid.toString())
|
||||||
|
|
||||||
printdbg(this, "new woridIndex: ${world.worldIndex}")
|
printdbg(this, "new worldIndex: ${world.worldIndex}")
|
||||||
printdbg(this, "worldCurrentlyPlaying: ${player.worldCurrentlyPlaying}")
|
printdbg(this, "worldCurrentlyPlaying: ${player.worldCurrentlyPlaying}")
|
||||||
|
|
||||||
actorNowPlaying = player
|
actorNowPlaying = player
|
||||||
actorGamer = player
|
actorGamer = player
|
||||||
forceAddActor(player)
|
forceAddActor(player)
|
||||||
|
|
||||||
|
WeatherMixer.internalReset()
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyToggler.forceSet(Input.Keys.Q, false)
|
KeyToggler.forceSet(Input.Keys.Q, false)
|
||||||
@@ -521,7 +532,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
|
|
||||||
// pie menu
|
// pie menu
|
||||||
uiPieMenu = UIQuickslotPie()
|
uiPieMenu = UIQuickslotPie()
|
||||||
uiPieMenu.setPosition(drawWidth / 2, App.scr.halfh)
|
uiPieMenu.setPosition(hdrawWidth, App.scr.halfh)
|
||||||
|
|
||||||
// vital metre
|
// vital metre
|
||||||
// fill in getter functions by
|
// fill in getter functions by
|
||||||
@@ -715,6 +726,10 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
|
|
||||||
gameUpdateGovernor.reset()
|
gameUpdateGovernor.reset()
|
||||||
|
|
||||||
|
if (UILoadGovernor.previousSaveWasLoaded) {
|
||||||
|
sendNotification(listOf(Lang["GAME_PREV_SAVE_WAS_LOADED1"], Lang["GAME_PREV_SAVE_WAS_LOADED2"]))
|
||||||
|
}
|
||||||
|
|
||||||
gameFullyLoaded = true
|
gameFullyLoaded = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -851,7 +866,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
//notifier.update(delta)
|
//notifier.update(delta)
|
||||||
// open/close fake blur UI according to what's opened
|
// open/close fake blur UI according to what's opened
|
||||||
if (uiInventoryPlayer.isVisible ||
|
if (uiInventoryPlayer.isVisible ||
|
||||||
getUIFixture.get()?.isVisible == true) {
|
getUIFixture.get()?.isVisible == true || worldTransitionOngoing) {
|
||||||
uiBlur.setAsOpen()
|
uiBlur.setAsOpen()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -867,6 +882,26 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
//println("paused = $paused")
|
//println("paused = $paused")
|
||||||
|
|
||||||
if ((!paused && !App.isScreenshotRequested()) && newWorldLoadedLatch) newWorldLoadedLatch = false
|
if ((!paused && !App.isScreenshotRequested()) && newWorldLoadedLatch) newWorldLoadedLatch = false
|
||||||
|
|
||||||
|
|
||||||
|
if (doThingsAfterSave) {
|
||||||
|
saveRequested2 = false
|
||||||
|
doThingsAfterSave = false
|
||||||
|
saveCallback!!()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (saveRequested2) {
|
||||||
|
saveRequested2 = false
|
||||||
|
doForceSave()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (worldTransitionPauseRequested > 0) { // let a frame to update before locking (=pausing) entirely
|
||||||
|
worldTransitionPauseRequested -= 1
|
||||||
|
}
|
||||||
|
else if (worldTransitionPauseRequested == 0) {
|
||||||
|
paused = true
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -901,6 +936,93 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
actorNowPlaying,
|
actorNowPlaying,
|
||||||
uiContainer// + uiFixture
|
uiContainer// + uiFixture
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// quick and dirty way to show
|
||||||
|
if (worldTransitionOngoing) {
|
||||||
|
batch.inUse {
|
||||||
|
batch.color = gradEndCol
|
||||||
|
Toolkit.fillArea(batch, 0, 0, App.scr.width, App.scr.height)
|
||||||
|
|
||||||
|
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
val t = Lang["MENU_IO_SAVING"]
|
||||||
|
val circleSheet = CommonResourcePool.getAsTextureRegionPack("loading_circle_64")
|
||||||
|
Toolkit.drawTextCentered(batch, App.fontGame, t, Toolkit.drawWidth, 0, ((App.scr.height - circleSheet.tileH) / 2) - 40)
|
||||||
|
|
||||||
|
// -1..63
|
||||||
|
val index =
|
||||||
|
((WriteSavegame.saveProgress / WriteSavegame.saveProgressMax) * circleSheet.horizontalCount * circleSheet.verticalCount).roundToInt() - 1
|
||||||
|
if (index >= 0) {
|
||||||
|
val sx = index % circleSheet.horizontalCount
|
||||||
|
val sy = index / circleSheet.horizontalCount
|
||||||
|
// q&d fix for ArrayIndexOutOfBoundsException caused when saving huge world... wut?
|
||||||
|
if (sx in 0 until circleSheet.horizontalCount && sy in 0 until circleSheet.horizontalCount) {
|
||||||
|
batch.draw(
|
||||||
|
circleSheet.get(sx, sy),
|
||||||
|
((Toolkit.drawWidth - circleSheet.tileW) / 2).toFloat(),
|
||||||
|
((App.scr.height - circleSheet.tileH) / 2).toFloat()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var worldTransitionOngoing = false
|
||||||
|
private var worldTransitionPauseRequested = -1
|
||||||
|
private var saveRequested2 = false
|
||||||
|
private var saveCallback: (() -> Unit)? = null
|
||||||
|
private var doThingsAfterSave = false
|
||||||
|
|
||||||
|
override fun requestForceSave(callback: () -> Unit) {
|
||||||
|
saveCallback = callback
|
||||||
|
worldTransitionOngoing = true
|
||||||
|
saveRequested2 = true
|
||||||
|
worldTransitionPauseRequested = 1
|
||||||
|
blockMarkingActor.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun doForceSave() {
|
||||||
|
// TODO show appropriate UI
|
||||||
|
// uiBlur.setAsOpen()
|
||||||
|
|
||||||
|
saveTheGame({ // onSuccessful
|
||||||
|
System.gc()
|
||||||
|
autosaveTimer = 0f
|
||||||
|
|
||||||
|
// TODO hide appropriate UI
|
||||||
|
uiBlur.setAsClose()
|
||||||
|
doThingsAfterSave = true
|
||||||
|
}, { // onError
|
||||||
|
// TODO show failure message
|
||||||
|
|
||||||
|
// TODO hide appropriate UI
|
||||||
|
uiBlur.setAsClose()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun saveTheGame(onSuccessful: () -> Unit, onError: (Throwable) -> Unit) {
|
||||||
|
val saveTime_t = App.getTIME_T()
|
||||||
|
val playerSavefile = getPlayerSaveFiledesc(INGAME.playerSavefileName)
|
||||||
|
val worldSavefile = getWorldSaveFiledesc(INGAME.worldSavefileName)
|
||||||
|
|
||||||
|
|
||||||
|
INGAME.makeSavegameBackupCopy(playerSavefile)
|
||||||
|
WriteSavegame(saveTime_t, WriteSavegame.SaveMode.PLAYER, INGAME.playerDisk, playerSavefile, INGAME as TerrarumIngame, false, onError) {
|
||||||
|
|
||||||
|
INGAME.makeSavegameBackupCopy(worldSavefile)
|
||||||
|
WriteSavegame(saveTime_t, WriteSavegame.SaveMode.WORLD, INGAME.worldDisk, worldSavefile, INGAME as TerrarumIngame, false, onError) {
|
||||||
|
// callback:
|
||||||
|
// rebuild the disk skimmers
|
||||||
|
INGAME.actorContainerActive.filterIsInstance<IngamePlayer>().forEach {
|
||||||
|
printdbg(this, "Game Save callback -- rebuilding the disk skimmer for IngamePlayer ${it.actorValue.getAsString(AVKey.NAME)}")
|
||||||
|
// it.rebuildingDiskSkimmer?.rebuild()
|
||||||
|
}
|
||||||
|
|
||||||
|
// return to normal state
|
||||||
|
onSuccessful()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val maxRenderableWires = ReferencingRanges.ACTORS_WIRES.last - ReferencingRanges.ACTORS_WIRES.first + 1
|
private val maxRenderableWires = ReferencingRanges.ACTORS_WIRES.last - ReferencingRanges.ACTORS_WIRES.first + 1
|
||||||
@@ -1107,13 +1229,13 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
uiAutosaveNotifier.setAsOpen()
|
uiAutosaveNotifier.setAsOpen()
|
||||||
|
|
||||||
val saveTime_t = App.getTIME_T()
|
val saveTime_t = App.getTIME_T()
|
||||||
val playerSavefile = getPlayerSaveFiledesc(INGAME.playerSavefileName)
|
val playerSavefile0 = getPlayerSaveFiledesc(INGAME.playerSavefileName)
|
||||||
val worldSavefile = getWorldSaveFiledesc(INGAME.worldSavefileName)
|
val worldSavefile0 = getWorldSaveFiledesc(INGAME.worldSavefileName)
|
||||||
|
|
||||||
INGAME.makeSavegameBackupCopy(playerSavefile)
|
val playerSavefile = INGAME.makeSavegameBackupCopyAuto(playerSavefile0)
|
||||||
WriteSavegame(saveTime_t, WriteSavegame.SaveMode.PLAYER, INGAME.playerDisk, playerSavefile, INGAME as TerrarumIngame, true, autosaveOnErrorAction) {
|
WriteSavegame(saveTime_t, WriteSavegame.SaveMode.PLAYER, INGAME.playerDisk, playerSavefile, INGAME as TerrarumIngame, true, autosaveOnErrorAction) {
|
||||||
|
|
||||||
INGAME.makeSavegameBackupCopy(worldSavefile)
|
val worldSavefile = INGAME.makeSavegameBackupCopyAuto(worldSavefile0)
|
||||||
WriteSavegame(saveTime_t, WriteSavegame.SaveMode.QUICK_WORLD, INGAME.worldDisk, worldSavefile, INGAME as TerrarumIngame, true, autosaveOnErrorAction) {
|
WriteSavegame(saveTime_t, WriteSavegame.SaveMode.QUICK_WORLD, INGAME.worldDisk, worldSavefile, INGAME as TerrarumIngame, true, autosaveOnErrorAction) {
|
||||||
// callback:
|
// callback:
|
||||||
// rebuild the disk skimmers
|
// rebuild the disk skimmers
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package net.torvald.terrarum.modulebasegame
|
package net.torvald.terrarum.modulebasegame
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx
|
import com.badlogic.gdx.Gdx
|
||||||
|
import com.badlogic.gdx.Input
|
||||||
import com.badlogic.gdx.InputAdapter
|
import com.badlogic.gdx.InputAdapter
|
||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||||
@@ -13,17 +14,20 @@ import net.torvald.random.HQRNG
|
|||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
import net.torvald.terrarum.App.printdbg
|
import net.torvald.terrarum.App.printdbg
|
||||||
import net.torvald.terrarum.App.printdbgerr
|
import net.torvald.terrarum.App.printdbgerr
|
||||||
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
|
||||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF
|
||||||
import net.torvald.terrarum.console.CommandDict
|
import net.torvald.terrarum.console.CommandDict
|
||||||
import net.torvald.terrarum.gameactors.*
|
import net.torvald.terrarum.gameactors.*
|
||||||
import net.torvald.terrarum.gameactors.ai.ActorAI
|
import net.torvald.terrarum.gameactors.ai.ActorAI
|
||||||
|
import net.torvald.terrarum.gamecontroller.KeyToggler
|
||||||
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
|
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
|
||||||
import net.torvald.terrarum.gameparticles.ParticleBase
|
import net.torvald.terrarum.gameparticles.ParticleBase
|
||||||
import net.torvald.terrarum.gameworld.GameWorld
|
import net.torvald.terrarum.gameworld.GameWorld
|
||||||
import net.torvald.terrarum.gameworld.WorldTime
|
import net.torvald.terrarum.gameworld.WorldTime
|
||||||
import net.torvald.terrarum.gameworld.fmod
|
import net.torvald.terrarum.gameworld.fmod
|
||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
|
import net.torvald.terrarum.modulebasegame.ui.UILoadGovernor
|
||||||
import net.torvald.terrarum.modulebasegame.ui.UIRemoCon
|
import net.torvald.terrarum.modulebasegame.ui.UIRemoCon
|
||||||
import net.torvald.terrarum.modulebasegame.ui.UITitleRemoConYaml
|
import net.torvald.terrarum.modulebasegame.ui.UITitleRemoConYaml
|
||||||
import net.torvald.terrarum.realestate.LandUtil
|
import net.torvald.terrarum.realestate.LandUtil
|
||||||
@@ -64,49 +68,72 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
|
|
||||||
private lateinit var demoWorld: GameWorld
|
private lateinit var demoWorld: GameWorld
|
||||||
private lateinit var cameraNodes: FloatArray // camera Y-pos
|
private lateinit var cameraNodes: FloatArray // camera Y-pos
|
||||||
|
private val cameraNodeWidth = 15
|
||||||
|
private val lookaheadDist = cameraNodeWidth * TILE_SIZED
|
||||||
|
private fun getPointAt(px: Double): Double {
|
||||||
|
val ww = TILE_SIZEF * demoWorld.width
|
||||||
|
val x = px % ww
|
||||||
|
|
||||||
|
val indexThis = ((x / ww * cameraNodes.size).floorInt())
|
||||||
|
val xwstart: Double = indexThis.toDouble() / cameraNodes.size * ww
|
||||||
|
val xwend: Double = ((indexThis + 1).toDouble() / cameraNodes.size) * ww
|
||||||
|
val xw: Double = xwend - xwstart
|
||||||
|
val xperc: Double = (x - xwstart) / xw
|
||||||
|
|
||||||
|
// return FastMath.interpolateLinear(xperc.toFloat(), cameraNodes[indexThis fmod cameraNodes.size], cameraNodes[(indexThis + 1) fmod cameraNodes.size]).toDouble()
|
||||||
|
return FastMath.interpolateCatmullRom(xperc.toFloat(),
|
||||||
|
cameraNodes[(indexThis - 1) fmod cameraNodes.size],
|
||||||
|
cameraNodes[(indexThis - 0) fmod cameraNodes.size],
|
||||||
|
cameraNodes[(indexThis + 1) fmod cameraNodes.size],
|
||||||
|
cameraNodes[(indexThis + 2) fmod cameraNodes.size]
|
||||||
|
).toDouble()
|
||||||
|
}
|
||||||
private val cameraAI = object : ActorAI {
|
private val cameraAI = object : ActorAI {
|
||||||
private var firstTime = true
|
private var firstTime = true
|
||||||
private val lookaheadDist = 100.0
|
|
||||||
|
|
||||||
private fun getPointAt(px: Double): Float {
|
|
||||||
val ww = TILE_SIZEF * demoWorld.width
|
|
||||||
val x = px % ww
|
|
||||||
|
|
||||||
val indexThis = ((x / ww * cameraNodes.size).floorInt()) fmod cameraNodes.size
|
|
||||||
val xwstart: Float = indexThis.toFloat() / cameraNodes.size * ww
|
|
||||||
val xwend: Float = ((indexThis + 1).toFloat() / cameraNodes.size) * ww
|
|
||||||
val xw: Float = xwend - xwstart
|
|
||||||
val xperc: Double = (x - xwstart) / xw
|
|
||||||
|
|
||||||
return FastMath.interpolateLinear(xperc.toFloat(), cameraNodes[indexThis], cameraNodes[(indexThis + 1) % cameraNodes.size])
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun update(actor: Actor, delta: Float) {
|
override fun update(actor: Actor, delta: Float) {
|
||||||
val ww = TILE_SIZEF * demoWorld.width
|
val ww = TILE_SIZEF * demoWorld.width
|
||||||
val actor = actor as CameraPlayer
|
val actor = actor as CameraPlayer
|
||||||
|
|
||||||
val px: Double = actor.hitbox.canonicalX + actor.actorValue.getAsDouble(AVKey.SPEED)!!
|
val stride = cos(actor.bearing1A) * actor.actorValue.getAsDouble(AVKey.SPEED)!!
|
||||||
val pxP = px - lookaheadDist * cos(actor.targetBearing)
|
|
||||||
val pxN = px + lookaheadDist * cos(actor.targetBearing)
|
|
||||||
|
|
||||||
val yP = getPointAt(pxP)
|
val x1 = actor.hitbox.startX// + stride
|
||||||
val yN = getPointAt(pxN)
|
val y1 = actor.hitbox.startY
|
||||||
|
|
||||||
val y = (yP + yN) / 2f
|
val px1L = x1 - lookaheadDist
|
||||||
|
val px1C = x1
|
||||||
|
val px1R = x1 + lookaheadDist
|
||||||
|
val py1L = getPointAt(px1L)
|
||||||
|
val py1C = getPointAt(px1C)
|
||||||
|
val py1R = getPointAt(px1R)
|
||||||
|
|
||||||
|
val px2L = (px1L + px1C) / 2.0
|
||||||
|
val px2R = (px1C + px1R) / 2.0
|
||||||
|
val py2L = (py1L + py1C) / 2.0
|
||||||
|
val py2R = (py1C + py1R) / 2.0
|
||||||
|
|
||||||
|
val x2 = (px2L + px2R) / 2
|
||||||
|
val y2 = (py2L + py2R) / 2
|
||||||
|
|
||||||
|
val theta = atan2(py2R - py2L, px2R - px2L)
|
||||||
|
|
||||||
if (firstTime) {
|
if (firstTime) {
|
||||||
firstTime = false
|
firstTime = false
|
||||||
actor.hitbox.setPositionY(y - 8.0)
|
actor.hitbox.setPosition(x1, getPointAt(x1))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//actor.moveTo(px, y - 8.0)
|
actor.bearing1A = atan2(py1C - py1L, px1C - px1L)
|
||||||
//actor.hitbox.setPosition(px, y - 8.0)
|
actor.bearing1B = atan2(py1R - py1C, px1R - px1C)
|
||||||
actor.moveTo(atan2((yN - yP).toDouble(), pxN - pxP))
|
actor.bearing2A = atan2(py2R - py2L, px2R - px2L)
|
||||||
|
actor.moveTo(theta)
|
||||||
|
// actor.hitbox.setPosition(x2, y2) // there is no reason it would work -- speed is wildly inconsistent as the angle reaches 90deg
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actor.hitbox.canonicalX > ww) {
|
if (actor.hitbox.startX > ww) {
|
||||||
actor.hitbox.translatePosX(-ww.toDouble())
|
actor.hitbox.translatePosX(-ww.toDouble())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private lateinit var cameraPlayer: ActorWithBody
|
private lateinit var cameraPlayer: ActorWithBody
|
||||||
@@ -122,9 +149,9 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
private lateinit var worldFBO: FloatFrameBuffer
|
private lateinit var worldFBO: FloatFrameBuffer
|
||||||
|
|
||||||
private val warning32bitJavaIcon = TextureRegion(Texture(Gdx.files.internal("assets/graphics/gui/32_bit_warning.tga")))
|
private val warning32bitJavaIcon = TextureRegion(Texture(Gdx.files.internal("assets/graphics/gui/32_bit_warning.tga")))
|
||||||
|
private val warningAppleRosettaIcon = TextureRegion(Texture(Gdx.files.internal("assets/graphics/gui/apple_rosetta_warning.tga")))
|
||||||
|
|
||||||
init {
|
init {
|
||||||
warning32bitJavaIcon.flip(false, false)
|
|
||||||
gameUpdateGovernor = ConsistentUpdateRate.also { it.reset() }
|
gameUpdateGovernor = ConsistentUpdateRate.also { it.reset() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +165,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
//ReadWorld.readWorldAndSetNewWorld(Terrarum.ingame!! as TerrarumIngame, reader)
|
//ReadWorld.readWorldAndSetNewWorld(Terrarum.ingame!! as TerrarumIngame, reader)
|
||||||
val world = ReadSimpleWorld(reader, file)
|
val world = ReadSimpleWorld(reader, file)
|
||||||
demoWorld = world
|
demoWorld = world
|
||||||
demoWorld.worldTime.timeDelta = 0//60
|
demoWorld.worldTime.timeDelta = 330 // a year = 8 minutes
|
||||||
printdbg(this, "Demo world loaded")
|
printdbg(this, "Demo world loaded")
|
||||||
}
|
}
|
||||||
catch (e: IOException) {
|
catch (e: IOException) {
|
||||||
@@ -152,7 +179,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
demoWorld.worldTime.addTime(WorldTime.DAY_LENGTH * 32)
|
demoWorld.worldTime.addTime(WorldTime.DAY_LENGTH * 32)
|
||||||
|
|
||||||
// construct camera nodes
|
// construct camera nodes
|
||||||
val nodeCount = demoWorld.width / 10
|
val nodeCount = demoWorld.width / cameraNodeWidth
|
||||||
cameraNodes = kotlin.FloatArray(nodeCount) {
|
cameraNodes = kotlin.FloatArray(nodeCount) {
|
||||||
val tileXPos = (demoWorld.width.toFloat() * it / nodeCount).floorInt()
|
val tileXPos = (demoWorld.width.toFloat() * it / nodeCount).floorInt()
|
||||||
var travelDownCounter = 0
|
var travelDownCounter = 0
|
||||||
@@ -237,6 +264,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
printdbg(this, "update list of savegames")
|
printdbg(this, "update list of savegames")
|
||||||
// to show "Continue" and "Load" on the titlescreen, uncomment this line
|
// to show "Continue" and "Load" on the titlescreen, uncomment this line
|
||||||
App.updateListOfSavegames()
|
App.updateListOfSavegames()
|
||||||
|
UILoadGovernor.reset()
|
||||||
|
|
||||||
|
|
||||||
loadThingsWhileIntroIsVisible()
|
loadThingsWhileIntroIsVisible()
|
||||||
@@ -253,9 +281,14 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val updateScreen = { delta: Float ->
|
private val updateScreen = { delta: Float ->
|
||||||
demoWorld.globalLight = WeatherMixer.globalLightNow
|
// TODO: desynched weather and time-of-day change
|
||||||
|
|
||||||
|
val forcedTime = 39693
|
||||||
|
// demoWorld.globalLight = WeatherMixer.globalLightNow
|
||||||
|
demoWorld.globalLight = WeatherMixer.getGlobalLightOfTime(demoWorld, forcedTime)
|
||||||
demoWorld.updateWorldTime(delta)
|
demoWorld.updateWorldTime(delta)
|
||||||
WeatherMixer.update(delta, cameraPlayer, demoWorld)
|
// WeatherMixer.update(delta, cameraPlayer, demoWorld)
|
||||||
|
WeatherMixer.forceTimeAt = forcedTime
|
||||||
cameraPlayer.update(delta)
|
cameraPlayer.update(delta)
|
||||||
|
|
||||||
// worldcamera update AFTER cameraplayer in this case; the other way is just an exception for actual ingame SFX
|
// worldcamera update AFTER cameraplayer in this case; the other way is just an exception for actual ingame SFX
|
||||||
@@ -268,6 +301,24 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
|
|
||||||
private val particles = CircularArray<ParticleBase>(16, true)
|
private val particles = CircularArray<ParticleBase>(16, true)
|
||||||
|
|
||||||
|
private fun drawLineOnWorld(x1: Float, y1: Float, x2: Float, y2: Float) {
|
||||||
|
val w = 2.0f
|
||||||
|
App.shapeRender.rectLine(
|
||||||
|
x1 - WorldCamera.x, App.scr.height - (y1 - WorldCamera.y),
|
||||||
|
x2 - WorldCamera.x, App.scr.height - (y2 - WorldCamera.y),
|
||||||
|
w
|
||||||
|
)
|
||||||
|
}
|
||||||
|
private fun drawLineOnWorld(x1: Double, y1: Double, x2: Double, y2: Double) {
|
||||||
|
val ww = demoWorld.width * TILE_SIZE
|
||||||
|
drawLineOnWorld(x1.toFloat(), y1.toFloat(), x2.toFloat(), y2.toFloat())
|
||||||
|
drawLineOnWorld(x1.toFloat() + ww, y1.toFloat(), x2.toFloat() + ww, y2.toFloat())
|
||||||
|
}
|
||||||
|
|
||||||
|
private val baseSlopeCol = Color(0f, 0.9f, 0.85f, 1f)
|
||||||
|
private val firstOrderSlopeCol = Color(0f, 0.4f, 0f, 1f)
|
||||||
|
private val secondOrderSlopeCol = Color(1f, 0.3f, 0.6f, 1f)
|
||||||
|
|
||||||
private val renderScreen = { delta: Float ->
|
private val renderScreen = { delta: Float ->
|
||||||
Gdx.graphics.setTitle(TerrarumIngame.getCanonicalTitle())
|
Gdx.graphics.setTitle(TerrarumIngame.getCanonicalTitle())
|
||||||
|
|
||||||
@@ -290,6 +341,52 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
particles,
|
particles,
|
||||||
uiContainer = uiContainer
|
uiContainer = uiContainer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (KeyToggler.isOn(Input.Keys.F10)) {
|
||||||
|
App.shapeRender.inUse {
|
||||||
|
|
||||||
|
val actor = cameraPlayer as CameraPlayer
|
||||||
|
|
||||||
|
val x1 = actor.hitbox.startX
|
||||||
|
val y1 = actor.hitbox.startY
|
||||||
|
|
||||||
|
val px1L = x1 - lookaheadDist// * cos(actor.bearing1A)
|
||||||
|
val px1C = x1
|
||||||
|
val px1R = x1 + lookaheadDist// * cos(actor.bearing1B)
|
||||||
|
val py1L = getPointAt(px1L)
|
||||||
|
val py1C = getPointAt(px1C)
|
||||||
|
val py1R = getPointAt(px1R)
|
||||||
|
|
||||||
|
val px2L = (px1L + px1C) / 2.0
|
||||||
|
val px2R = (px1C + px1R) / 2.0
|
||||||
|
val py2L = (py1L + py1C) / 2.0
|
||||||
|
val py2R = (py1C + py1R) / 2.0
|
||||||
|
|
||||||
|
it.color = firstOrderSlopeCol
|
||||||
|
drawLineOnWorld(px1L, py1L, px1C, py1C)
|
||||||
|
drawLineOnWorld(px1C, py1C, px1R, py1R)
|
||||||
|
|
||||||
|
/*(1..cameraNodes.lastIndex + 16).forEach { index0 ->
|
||||||
|
val x1 = (index0 - 1) * cameraNodeWidth * TILE_SIZEF; val x2 = (index0 - 0) * cameraNodeWidth * TILE_SIZEF
|
||||||
|
val y1 = cameraNodes[(index0 - 1) fmod cameraNodes.size]; val y2 = cameraNodes[index0 fmod cameraNodes.size]
|
||||||
|
drawLineOnWorld(x1, y1, x2, y2)
|
||||||
|
}*/
|
||||||
|
it.color = baseSlopeCol
|
||||||
|
val points = (0..App.scr.width).map { x ->
|
||||||
|
val worldX = (WorldCamera.x + x).toDouble()
|
||||||
|
worldX to getPointAt(worldX)
|
||||||
|
}
|
||||||
|
points.forEachIndexed { index, (x, y) ->
|
||||||
|
if (index > 0) {
|
||||||
|
drawLineOnWorld(points[index - 1].first, points[index - 1].second, x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it.color = secondOrderSlopeCol
|
||||||
|
drawLineOnWorld(px2L, py2L, px2R, py2R)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printdbgerr(this, "Demoworld is already been destroyed")
|
printdbgerr(this, "Demoworld is already been destroyed")
|
||||||
@@ -332,16 +429,34 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
|
|
||||||
batch.color = Color.WHITE
|
batch.color = Color.WHITE
|
||||||
|
|
||||||
if (App.is32BitJVM && uiRemoCon.currentRemoConContents.parent == null) {
|
// warn: 32-bit
|
||||||
// if (uiRemoCon.currentRemoConContents.parent == null) {
|
val linegap = 4
|
||||||
val linegap = 4
|
val imgTxtGap = 10
|
||||||
val imgTxtGap = 10
|
val yoff = App.scr.height - App.scr.tvSafeGraphicsHeight - 64 - (3*(20+linegap)) - imgTxtGap - 9
|
||||||
val yoff = App.scr.height - App.scr.tvSafeGraphicsHeight - 64 - (3*(20+linegap)) - imgTxtGap - 9
|
if (uiRemoCon.currentRemoConContents.parent == null) {
|
||||||
Toolkit.drawCentered(batch, warning32bitJavaIcon, yoff)
|
var texts = emptyList<String>()
|
||||||
for (i in 0..2) {
|
var textcols = emptyList<Color>()
|
||||||
val text = Lang.get("GAME_32BIT_WARNING${i+1}", (i != 2))
|
if (App.is32BitJVM) {
|
||||||
if (i == 2) batch.color = Toolkit.Theme.COL_SELECTED
|
Toolkit.drawCentered(batch, warning32bitJavaIcon, yoff)
|
||||||
App.fontGame.draw(batch, text, ((drawWidth - App.fontGame.getWidth(text)) / 2).toFloat(), yoff + imgTxtGap + 64f + linegap + i*(20+linegap))
|
texts = (1..3).map { Lang.get("GAME_32BIT_WARNING$it", (it != 3)) }
|
||||||
|
textcols = (1..3).map { if (it == 3) Toolkit.Theme.COL_SELECTED else Color.WHITE }
|
||||||
|
}
|
||||||
|
// warn: rosetta on Apple M-chips
|
||||||
|
else if (App.getUndesirableConditions() == "apple_execution_through_rosetta") {
|
||||||
|
Toolkit.drawCentered(batch, warningAppleRosettaIcon, yoff)
|
||||||
|
texts = (1..2).map { Lang.get("GAME_APPLE_ROSETTA_WARNING$it") }
|
||||||
|
textcols = texts.map { Color.WHITE }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
texts.forEachIndexed { i, text ->
|
||||||
|
batch.color = textcols[i]
|
||||||
|
App.fontGame.draw(
|
||||||
|
batch,
|
||||||
|
text,
|
||||||
|
((drawWidth - App.fontGame.getWidth(text)) / 2).toFloat(),
|
||||||
|
yoff + imgTxtGap + 64f + linegap + i * (20 + linegap)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -379,6 +494,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
uiRemoCon.dispose()
|
uiRemoCon.dispose()
|
||||||
demoWorld.dispose()
|
demoWorld.dispose()
|
||||||
warning32bitJavaIcon.texture.dispose()
|
warning32bitJavaIcon.texture.dispose()
|
||||||
|
warningAppleRosettaIcon.texture.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun inputStrobed(e: TerrarumKeyboardEvent) {
|
override fun inputStrobed(e: TerrarumKeyboardEvent) {
|
||||||
@@ -435,7 +551,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
override val hitbox = Hitbox(0.0, 0.0, 2.0, 2.0)
|
override val hitbox = Hitbox(0.0, 0.0, 2.0, 2.0)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
actorValue[AVKey.SPEED] = 1.666
|
actorValue[AVKey.SPEED] = 1.666 * (if (Math.random() < 1.0 / 65536.0) -1 else 1) // some easter egg
|
||||||
hitbox.setPosition(
|
hitbox.setPosition(
|
||||||
HQRNG().nextInt(demoWorld.width) * TILE_SIZED,
|
HQRNG().nextInt(demoWorld.width) * TILE_SIZED,
|
||||||
0.0 // Y pos: placeholder; camera AI will take it over
|
0.0 // Y pos: placeholder; camera AI will take it over
|
||||||
@@ -475,7 +591,14 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var targetBearing = 0.0
|
var targetBearing = 0.0
|
||||||
var currentBearing = Double.NaN
|
var currentBearing = 0.0
|
||||||
|
|
||||||
|
var bearing1A = 0.0
|
||||||
|
var bearing1B = 0.0
|
||||||
|
var bearing1C = 0.0
|
||||||
|
var bearing2A = 0.0
|
||||||
|
var bearing2B = 0.0
|
||||||
|
var bearing3A = 0.0
|
||||||
|
|
||||||
override fun moveTo(bearing: Double) {
|
override fun moveTo(bearing: Double) {
|
||||||
targetBearing = bearing
|
targetBearing = bearing
|
||||||
@@ -495,6 +618,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|||||||
|
|
||||||
val xdiff = if (xdiff1 < 0) xdiff2 else xdiff1
|
val xdiff = if (xdiff1 < 0) xdiff2 else xdiff1
|
||||||
val ydiff = toY - hitbox.canonicalY
|
val ydiff = toY - hitbox.canonicalY
|
||||||
|
|
||||||
moveTo(atan2(ydiff, xdiff))
|
moveTo(atan2(ydiff, xdiff))
|
||||||
hitbox.setPositionX(hitbox.canonicalX % ww)
|
hitbox.setPositionX(hitbox.canonicalX % ww)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,111 @@ import org.dyn4j.geometry.Vector2
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
typealias BlockBoxIndex = Int
|
typealias BlockBoxIndex = Int
|
||||||
|
typealias WireEmissionType = String
|
||||||
|
|
||||||
interface Electric {
|
open class Electric : FixtureBase {
|
||||||
val wireEmitterTypes: HashMap<String, BlockBoxIndex>
|
|
||||||
val wireEmission: HashMap<BlockBoxIndex, Vector2>
|
protected constructor() : super() {
|
||||||
val wireConsumption: HashMap<BlockBoxIndex, Vector2>
|
oldSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Making the sprite: do not address the CommonResourcePool directly; just do it like this snippet:
|
||||||
|
*
|
||||||
|
* ```makeNewSprite(FixtureBase.getSpritesheet("basegame", "sprites/fixtures/tiki_torch.tga", 16, 32))```
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
blockBox0: BlockBox,
|
||||||
|
blockBoxProps: BlockBoxProps = BlockBoxProps(0),
|
||||||
|
renderOrder: RenderOrder = RenderOrder.MIDDLE,
|
||||||
|
nameFun: () -> String,
|
||||||
|
mainUI: UICanvas? = null,
|
||||||
|
inventory: FixtureInventory? = null,
|
||||||
|
id: ActorID? = null
|
||||||
|
) : super(renderOrder, PhysProperties.IMMOBILE, id) {
|
||||||
|
blockBox = blockBox0
|
||||||
|
setHitboxDimension(TILE_SIZE * blockBox.width, TILE_SIZE * blockBox.height, 0, 0)
|
||||||
|
this.blockBoxProps = blockBoxProps
|
||||||
|
this.renderOrder = renderOrder
|
||||||
|
this.nameFun = nameFun
|
||||||
|
this.mainUI = mainUI
|
||||||
|
this.inventory = inventory
|
||||||
|
|
||||||
|
if (mainUI != null)
|
||||||
|
App.disposables.add(mainUI)
|
||||||
|
|
||||||
|
oldSinkStatus = Array(blockBox.width * blockBox.height) { Vector2() }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val ELECTIC_THRESHOLD_HIGH = 0.9
|
||||||
|
const val ELECTRIC_THRESHOLD_LOW = 0.1
|
||||||
|
const val ELECTRIC_THRESHOLD_EDGE_DELTA = 0.7
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getWireEmitterAt(point: Point2i) = this.wireEmitterTypes[pointToBlockBoxIndex(point)]
|
||||||
|
fun getWireEmitterAt(x: Int, y: Int) = this.wireEmitterTypes[pointToBlockBoxIndex(x, y)]
|
||||||
|
fun getWireSinkAt(point: Point2i) = this.wireSinkTypes[pointToBlockBoxIndex(point)]
|
||||||
|
fun getWireSinkAt(x: Int, y: Int) = this.wireSinkTypes[pointToBlockBoxIndex(x, y)]
|
||||||
|
|
||||||
|
fun setWireEmitterAt(x: Int, y: Int, type: WireEmissionType) { wireEmitterTypes[pointToBlockBoxIndex(x, y)] = type }
|
||||||
|
fun setWireSinkAt(x: Int, y: Int, type: WireEmissionType) { wireSinkTypes[pointToBlockBoxIndex(x, y)] = type }
|
||||||
|
fun setWireEmissionAt(x: Int, y: Int, emission: Vector2) { wireEmission[pointToBlockBoxIndex(x, y)] = emission }
|
||||||
|
fun setWireConsumptionAt(x: Int, y: Int, consumption: Vector2) { wireConsumption[pointToBlockBoxIndex(x, y)] = consumption }
|
||||||
|
|
||||||
|
@Transient val wireEmitterTypes: HashMap<BlockBoxIndex, WireEmissionType> = HashMap()
|
||||||
|
@Transient val wireSinkTypes: HashMap<BlockBoxIndex, WireEmissionType> = HashMap()
|
||||||
|
@Transient val wireEmission: HashMap<BlockBoxIndex, Vector2> = HashMap()
|
||||||
|
@Transient val wireConsumption: HashMap<BlockBoxIndex, Vector2> = HashMap()
|
||||||
|
|
||||||
|
/** Triggered when 'digital_bit' rises from low to high. Edge detection only considers the real component (labeled as 'x') of the vector */
|
||||||
|
open fun onRisingEdge(readFrom: BlockBoxIndex) {}
|
||||||
|
/** Triggered when 'digital_bit' rises from high to low. Edge detection only considers the real component (labeled as 'x') of the vector */
|
||||||
|
open fun onFallingEdge(readFrom: BlockBoxIndex) {}
|
||||||
|
/** Triggered when 'digital_bit' is held high. This function WILL NOT be triggered simultaneously with the rising edge. Level detection only considers the real component (labeled as 'x') of the vector */
|
||||||
|
open fun onSignalHigh(readFrom: BlockBoxIndex) {}
|
||||||
|
/** Triggered when 'digital_bit' is held low. This function WILL NOT be triggered simultaneously with the falling edge. Level detection only considers the real component (labeled as 'x') of the vector */
|
||||||
|
open fun onSignalLow(readFrom: BlockBoxIndex) {}
|
||||||
|
|
||||||
|
|
||||||
|
private val oldSinkStatus: Array<Vector2>
|
||||||
|
|
||||||
|
open fun updateOnWireGraphTraversal(offsetX: Int, offsetY: Int, sinkType: WireEmissionType) {
|
||||||
|
val index = pointToBlockBoxIndex(offsetX, offsetY)
|
||||||
|
val old = oldSinkStatus[index]
|
||||||
|
val wx = offsetX + intTilewiseHitbox.startX.toInt()
|
||||||
|
val wy = offsetY + intTilewiseHitbox.startY.toInt()
|
||||||
|
val new = WireCodex.getAllWiresThatAccepts("digital_bit").fold(Vector2()) { acc, (id, _) ->
|
||||||
|
INGAME.world.getWireEmitStateOf(wx, wy, id).let {
|
||||||
|
Vector2(acc.x + (it?.x ?: 0.0), acc.y + (it?.y ?: 0.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sinkType == "digital_bit") {
|
||||||
|
if (new.x - old.x >= ELECTRIC_THRESHOLD_EDGE_DELTA && new.x >= ELECTIC_THRESHOLD_HIGH)
|
||||||
|
onRisingEdge(index)
|
||||||
|
else if (old.x - new.x >= ELECTRIC_THRESHOLD_EDGE_DELTA && new.x <= ELECTRIC_THRESHOLD_LOW)
|
||||||
|
onFallingEdge(index)
|
||||||
|
else if (new.x >= ELECTIC_THRESHOLD_HIGH)
|
||||||
|
onSignalHigh(index)
|
||||||
|
else if (new.y <= ELECTRIC_THRESHOLD_LOW)
|
||||||
|
onSignalLow(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(delta: Float) {
|
||||||
|
super.update(delta)
|
||||||
|
oldSinkStatus.indices.forEach { index ->
|
||||||
|
val wx = (index % blockBox.width) + intTilewiseHitbox.startX.toInt()
|
||||||
|
val wy = (index / blockBox.width) + intTilewiseHitbox.startY.toInt()
|
||||||
|
val new = WireCodex.getAllWiresThatAccepts(getWireSinkAt(index % blockBox.width, index / blockBox.width) ?: "").fold(Vector2()) { acc, (id, _) ->
|
||||||
|
INGAME.world.getWireEmitStateOf(wx, wy, id).let {
|
||||||
|
Vector2(acc.x + (it?.x ?: 0.0), acc.y + (it?.y ?: 0.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oldSinkStatus[index].set(new)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,15 +135,20 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
|
|||||||
protected set
|
protected set
|
||||||
|
|
||||||
lateinit var blockBox: BlockBox // something like TapestryObject will want to redefine this
|
lateinit var blockBox: BlockBox // something like TapestryObject will want to redefine this
|
||||||
|
|
||||||
fun blockBoxIndexToPoint2i(it: BlockBoxIndex): Point2i = this.blockBox.width.let { w -> Point2i(it % w, it / w) }
|
fun blockBoxIndexToPoint2i(it: BlockBoxIndex): Point2i = this.blockBox.width.let { w -> Point2i(it % w, it / w) }
|
||||||
var blockBoxProps: BlockBoxProps = BlockBoxProps(0)
|
fun pointToBlockBoxIndex(point: Point2i) = point.y * this.blockBox.width + point.x
|
||||||
|
fun pointToBlockBoxIndex(x: Int, y: Int) = y * this.blockBox.width + x
|
||||||
|
|
||||||
|
@Transient var blockBoxProps: BlockBoxProps = BlockBoxProps(0)
|
||||||
@Transient var nameFun: () -> String = { "" }
|
@Transient var nameFun: () -> String = { "" }
|
||||||
@Transient var mainUI: UICanvas? = null
|
@Transient var mainUI: UICanvas? = null
|
||||||
var inventory: FixtureInventory? = null
|
var inventory: FixtureInventory? = null
|
||||||
|
|
||||||
protected var actorThatInstalledThisFixture: UUID? = null
|
protected var actorThatInstalledThisFixture: UUID? = null
|
||||||
|
|
||||||
private constructor() : super(RenderOrder.BEHIND, PhysProperties.IMMOBILE, null)
|
protected constructor() : super(RenderOrder.BEHIND, PhysProperties.IMMOBILE, null)
|
||||||
|
protected constructor(renderOrder: RenderOrder, physProp: PhysProperties, id: ActorID?) : super(renderOrder, physProp, id)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -357,10 +462,10 @@ interface CuedByWireChange {
|
|||||||
* Standard 32-bit binary flags.
|
* Standard 32-bit binary flags.
|
||||||
*
|
*
|
||||||
* (LSB)
|
* (LSB)
|
||||||
* - 0: fluid resist - when FALSE, the fixture will break itself to item/nothing.
|
* - 0: fluid intolerance - when SET, the fixture will break itself to item/nothing (depends on the flag #1).
|
||||||
* For example, crops has this flag FALSE.
|
* For example, crops have this flag SET.
|
||||||
* - 1: don't drop item when broken - when TRUE, the fixture will simply disappear instead of
|
* - 1: no drops - when SET, the fixture will simply disappear instead of dropping itself.
|
||||||
* dropping itself. For example, crop has this flag TRUE.
|
* For example, crops have this flag SET.
|
||||||
*
|
*
|
||||||
* (MSB)
|
* (MSB)
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
package net.torvald.terrarum.modulebasegame.gameactors
|
package net.torvald.terrarum.modulebasegame.gameactors
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Texture
|
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
|
||||||
import net.torvald.terrarum.CommonResourcePool
|
|
||||||
import net.torvald.terrarum.ModMgr
|
|
||||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||||
import net.torvald.terrarum.gameactors.AVKey
|
import net.torvald.terrarum.gameactors.AVKey
|
||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
@@ -11,12 +7,7 @@ import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
|
|||||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||||
import org.dyn4j.geometry.Vector2
|
import org.dyn4j.geometry.Vector2
|
||||||
|
|
||||||
class FixtureLogicSignalEmitter : FixtureBase, Electric {
|
class FixtureLogicSignalEmitter : Electric {
|
||||||
|
|
||||||
override val wireEmitterTypes: HashMap<String, BlockBoxIndex> = HashMap()
|
|
||||||
override val wireEmission: HashMap<BlockBoxIndex, Vector2> = HashMap()
|
|
||||||
override val wireConsumption: HashMap<BlockBoxIndex, Vector2> = HashMap()
|
|
||||||
|
|
||||||
|
|
||||||
constructor() : super(
|
constructor() : super(
|
||||||
BlockBox(BlockBox.NO_COLLISION, 1, 1),
|
BlockBox(BlockBox.NO_COLLISION, 1, 1),
|
||||||
@@ -34,14 +25,9 @@ class FixtureLogicSignalEmitter : FixtureBase, Electric {
|
|||||||
}
|
}
|
||||||
|
|
||||||
actorValue[AVKey.BASEMASS] = MASS
|
actorValue[AVKey.BASEMASS] = MASS
|
||||||
}
|
|
||||||
|
|
||||||
override fun update(delta: Float) {
|
setWireEmitterAt(0, 0, "digital_bit")
|
||||||
// the values does not get preserved on save reload??
|
setWireEmissionAt(0, 0, Vector2(1.0, 0.0))
|
||||||
wireEmitterTypes["digital_bit"] = 0
|
|
||||||
wireEmission[0] = Vector2(1.0, 0.0)
|
|
||||||
|
|
||||||
super.update(delta)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() { }
|
override fun dispose() { }
|
||||||
|
|||||||
@@ -1,22 +1,47 @@
|
|||||||
package net.torvald.terrarum.modulebasegame.gameactors
|
package net.torvald.terrarum.modulebasegame.gameactors
|
||||||
|
|
||||||
|
import net.torvald.random.XXHash64
|
||||||
|
import net.torvald.terrarum.App
|
||||||
|
import net.torvald.terrarum.App.printdbg
|
||||||
|
import net.torvald.terrarum.INGAME
|
||||||
|
import net.torvald.terrarum.Terrarum
|
||||||
|
import net.torvald.terrarum.WireCodex
|
||||||
import net.torvald.terrarum.gameactors.AVKey
|
import net.torvald.terrarum.gameactors.AVKey
|
||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
|
import net.torvald.terrarum.modulebasegame.WorldgenLoadScreen
|
||||||
|
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory.Companion.CAPACITY_MODE_WEIGHT
|
||||||
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
|
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
|
||||||
|
import net.torvald.terrarum.modulebasegame.serialise.LoadSavegame
|
||||||
|
import net.torvald.terrarum.modulebasegame.serialise.ReadActor
|
||||||
|
import net.torvald.terrarum.modulebasegame.ui.UILoadGovernor
|
||||||
import net.torvald.terrarum.modulebasegame.ui.UIWorldPortal
|
import net.torvald.terrarum.modulebasegame.ui.UIWorldPortal
|
||||||
|
import net.torvald.terrarum.savegame.ByteArray64Reader
|
||||||
|
import net.torvald.terrarum.savegame.DiskSkimmer
|
||||||
|
import net.torvald.terrarum.savegame.VDFileID
|
||||||
|
import net.torvald.terrarum.serialise.Common
|
||||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||||
|
import org.dyn4j.geometry.Vector2
|
||||||
|
import java.util.HashMap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by minjaesong on 2023-05-28.
|
* Created by minjaesong on 2023-05-28.
|
||||||
*/
|
*/
|
||||||
class FixtureWorldPortal : FixtureBase {
|
class FixtureWorldPortal : Electric {
|
||||||
|
|
||||||
constructor() : super(
|
constructor() : super(
|
||||||
BlockBox(BlockBox.NO_COLLISION, 5, 2),
|
BlockBox(BlockBox.NO_COLLISION, 5, 2),
|
||||||
nameFun = { Lang["ITEM_WORLD_PORTAL"] },
|
nameFun = { Lang["ITEM_WORLD_PORTAL"] },
|
||||||
mainUI = UIWorldPortal()
|
mainUI = UIWorldPortal(),
|
||||||
|
// inventory = FixtureInventory(200, CAPACITY_MODE_WEIGHT)
|
||||||
) {
|
) {
|
||||||
// TODO do something with (mainUI as UIWorldPortal).***
|
// TODO do something with (mainUI as UIWorldPortal).***
|
||||||
|
// (mainUI as UIWorldPortal).let { ui ->
|
||||||
|
// ui.transitionalCargo.chestInventory = this.inventory!!
|
||||||
|
// ui.transitionalCargo.chestNameFun = this.nameFun
|
||||||
|
// }
|
||||||
|
|
||||||
|
(mainUI as UIWorldPortal).host = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -30,6 +55,60 @@ class FixtureWorldPortal : FixtureBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
actorValue[AVKey.BASEMASS] = FixtureLogicSignalEmitter.MASS
|
actorValue[AVKey.BASEMASS] = FixtureLogicSignalEmitter.MASS
|
||||||
|
|
||||||
|
setWireSinkAt(2, 1, "digital_bit")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transient internal var teleportRequest: TeleportRequest? = null
|
||||||
|
|
||||||
|
override fun update(delta: Float) {
|
||||||
|
super.update(delta)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRisingEdge(readFrom: BlockBoxIndex) {
|
||||||
|
printdbg(this, "teleport! $teleportRequest")
|
||||||
|
teleportRequest?.let {
|
||||||
|
if (it.worldDiskToLoad != null && it.worldLoadParam != null) {
|
||||||
|
throw InternalError("Contradiction -- worldDiskToLoad and worldLoadParam are both not null: $teleportRequest")
|
||||||
|
}
|
||||||
|
|
||||||
|
val player = INGAME.actorGamer
|
||||||
|
|
||||||
|
// load existing
|
||||||
|
val jobAfterSave: () -> Unit
|
||||||
|
if (it.worldDiskToLoad != null) {
|
||||||
|
UILoadGovernor.worldDisk = it.worldDiskToLoad
|
||||||
|
UILoadGovernor.playerDisk = App.savegamePlayers[player.uuid]!!.files[0]
|
||||||
|
jobAfterSave = {
|
||||||
|
UILoadGovernor.playerDisk!!.rebuild()
|
||||||
|
LoadSavegame(UILoadGovernor.playerDisk!!, UILoadGovernor.worldDisk!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// create new
|
||||||
|
else {
|
||||||
|
jobAfterSave = {
|
||||||
|
val wx = it.worldLoadParam!!.width
|
||||||
|
val wy = it.worldLoadParam!!.height
|
||||||
|
val seed = it.worldLoadParam!!.worldGenSeed
|
||||||
|
val name = it.worldLoadParam!!.savegameName
|
||||||
|
printdbg(this, "generate for teleportation! Size=${wx}x${wy}, Name=$name, Seed=$seed")
|
||||||
|
|
||||||
|
val ingame = TerrarumIngame(App.batch)
|
||||||
|
val worldParam = TerrarumIngame.NewGameParams(player, it.worldLoadParam)
|
||||||
|
ingame.gameLoadInfoPayload = worldParam
|
||||||
|
ingame.gameLoadMode = TerrarumIngame.GameLoadMode.CREATE_NEW
|
||||||
|
|
||||||
|
Terrarum.setCurrentIngameInstance(ingame)
|
||||||
|
val loadScreen = WorldgenLoadScreen(ingame, wx, wy)
|
||||||
|
App.setLoadScreen(loadScreen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INGAME.requestForceSave(jobAfterSave)
|
||||||
|
|
||||||
|
|
||||||
|
teleportRequest = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun reload() {
|
override fun reload() {
|
||||||
@@ -37,4 +116,9 @@ class FixtureWorldPortal : FixtureBase {
|
|||||||
|
|
||||||
// TODO do something with (mainUI as UIWorldPortal).***
|
// TODO do something with (mainUI as UIWorldPortal).***
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal data class TeleportRequest(
|
||||||
|
val worldDiskToLoad: DiskSkimmer?, // for loading existing worlds
|
||||||
|
val worldLoadParam: TerrarumIngame.NewWorldParameters? // for creating new world
|
||||||
|
)
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,7 @@ class PhysTestBall : ActorWithBody(RenderOrder.MIDDLE, PhysProperties.PHYSICS_OB
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun drawBody(batch: SpriteBatch) {
|
override fun drawBody(batch: SpriteBatch) {
|
||||||
Terrarum.inShapeRenderer {
|
/*Terrarum.inShapeRenderer {
|
||||||
it.color = color
|
it.color = color
|
||||||
it.circle(
|
it.circle(
|
||||||
hitbox.startX.toFloat() - 1f,
|
hitbox.startX.toFloat() - 1f,
|
||||||
@@ -44,7 +44,7 @@ class PhysTestBall : ActorWithBody(RenderOrder.MIDDLE, PhysProperties.PHYSICS_OB
|
|||||||
hitbox.startY.toFloat() - 1f,
|
hitbox.startY.toFloat() - 1f,
|
||||||
hitbox.width.toFloat()
|
hitbox.width.toFloat()
|
||||||
)
|
)
|
||||||
}
|
}*/
|
||||||
|
|
||||||
//println(moveDelta)
|
//println(moveDelta)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ open class FixtureItemBase(originalID: ItemID, val fixtureClassName: String) : G
|
|||||||
|
|
||||||
(INGAME as TerrarumIngame).blockMarkingActor.let {
|
(INGAME as TerrarumIngame).blockMarkingActor.let {
|
||||||
it.setGhost(ghostItem.get())
|
it.setGhost(ghostItem.get())
|
||||||
it.isVisible = true
|
|
||||||
it.update(delta)
|
it.update(delta)
|
||||||
it.setGhostColourBlock()
|
it.setGhostColourBlock()
|
||||||
mouseInInteractableRange(actor) { it.setGhostColourAllow(); 0L }
|
mouseInInteractableRange(actor) { it.setGhostColourAllow(); 0L }
|
||||||
@@ -80,7 +79,6 @@ open class FixtureItemBase(originalID: ItemID, val fixtureClassName: String) : G
|
|||||||
|
|
||||||
(INGAME as TerrarumIngame).blockMarkingActor.let {
|
(INGAME as TerrarumIngame).blockMarkingActor.let {
|
||||||
it.unsetGhost()
|
it.unsetGhost()
|
||||||
it.isVisible = false
|
|
||||||
it.setGhostColourNone()
|
it.setGhostColourNone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class WireGraphDebugger(originalID: ItemID) : GameItem(originalID) {
|
|||||||
val wireName = WireCodex[itemID].nameKey
|
val wireName = WireCodex[itemID].nameKey
|
||||||
|
|
||||||
val emit = simCell.emt
|
val emit = simCell.emt
|
||||||
val recv = simCell.rcv
|
val recv = simCell.rcp
|
||||||
|
|
||||||
sb.append("$connexionIcon $wireName")
|
sb.append("$connexionIcon $wireName")
|
||||||
sb.append("\nE: $emit")
|
sb.append("\nE: $emit")
|
||||||
|
|||||||
@@ -1,35 +1,5 @@
|
|||||||
package net.torvald.terrarum.modulebasegame.serialise
|
package net.torvald.terrarum.modulebasegame.serialise
|
||||||
|
|
||||||
import net.torvald.gdx.graphics.PixmapIO2
|
|
||||||
import net.torvald.terrarum.App.printdbg
|
|
||||||
import net.torvald.terrarum.ItemCodex
|
|
||||||
import net.torvald.terrarum.ModMgr
|
|
||||||
import net.torvald.terrarum.ReferencingRanges.PREFIX_DYNAMICITEM
|
|
||||||
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
|
||||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase
|
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
|
|
||||||
import net.torvald.terrarum.realestate.LandUtil
|
|
||||||
import net.torvald.terrarum.toInt
|
|
||||||
import net.torvald.terrarum.savegame.*
|
|
||||||
import net.torvald.terrarum.savegame.VDFileID.LOADORDER
|
|
||||||
import net.torvald.terrarum.savegame.VDFileID.ROOT
|
|
||||||
import net.torvald.terrarum.savegame.VDFileID.SAVEGAMEINFO
|
|
||||||
import net.torvald.terrarum.savegame.VDFileID.THUMBNAIL
|
|
||||||
import net.torvald.terrarum.serialise.Common
|
|
||||||
import java.io.File
|
|
||||||
import java.util.zip.GZIPOutputStream
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Will happily overwrite existing entry
|
|
||||||
*/
|
|
||||||
private fun addFile(disk: VirtualDisk, file: DiskEntry) {
|
|
||||||
disk.entries[file.entryID] = file
|
|
||||||
file.parentEntryID = 0
|
|
||||||
val dir = VDUtil.getAsDirectory(disk, 0)
|
|
||||||
if (!dir.contains(file.entryID)) dir.add(file.entryID)
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class SavingThread(private val errorHandler: (Throwable) -> Unit) : Runnable {
|
abstract class SavingThread(private val errorHandler: (Throwable) -> Unit) : Runnable {
|
||||||
abstract fun save()
|
abstract fun save()
|
||||||
@@ -45,196 +15,4 @@ abstract class SavingThread(private val errorHandler: (Throwable) -> Unit) : Run
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
const val SCREENCAP_WAIT_TRY_MAX = 256
|
||||||
* Created by minjaesong on 2021-09-14.
|
|
||||||
*/
|
|
||||||
class WorldSavingThread(
|
|
||||||
val time_t: Long,
|
|
||||||
val disk: VirtualDisk,
|
|
||||||
val outFile: File,
|
|
||||||
val ingame: TerrarumIngame,
|
|
||||||
val hasThumbnail: Boolean,
|
|
||||||
val isAuto: Boolean,
|
|
||||||
val callback: () -> Unit,
|
|
||||||
val errorHandler: (Throwable) -> Unit
|
|
||||||
) : SavingThread(errorHandler) {
|
|
||||||
|
|
||||||
override fun save() {
|
|
||||||
|
|
||||||
disk.saveMode = 2 * isAuto.toInt() // no quick
|
|
||||||
disk.saveKind = VDSaveKind.WORLD_DATA
|
|
||||||
|
|
||||||
if (hasThumbnail) {
|
|
||||||
while (!IngameRenderer.fboRGBexportedLatch) {
|
|
||||||
Thread.sleep(1L)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val allTheActors = ingame.actorContainerActive.cloneToList() + ingame.actorContainerInactive.cloneToList()
|
|
||||||
|
|
||||||
val playersList: List<IngamePlayer> = allTheActors.filterIsInstance<IngamePlayer>()
|
|
||||||
val actorsList = allTheActors.filter { WriteWorld.actorAcceptable(it) }
|
|
||||||
val layers = intArrayOf(0,1).map { ingame.world.getLayer(it) }
|
|
||||||
val cw = ingame.world.width / LandUtil.CHUNK_W
|
|
||||||
val ch = ingame.world.height / LandUtil.CHUNK_H
|
|
||||||
|
|
||||||
WriteSavegame.saveProgress = 0f
|
|
||||||
WriteSavegame.saveProgressMax = 3f + (cw * ch * layers.size) + actorsList.size
|
|
||||||
|
|
||||||
|
|
||||||
val tgaout = ByteArray64GrowableOutputStream()
|
|
||||||
val gzout = GZIPOutputStream(tgaout)
|
|
||||||
|
|
||||||
printdbg(this, "Writing metadata...")
|
|
||||||
|
|
||||||
val creation_t = ingame.world.creationTime
|
|
||||||
|
|
||||||
|
|
||||||
// Write subset of Ingame.ItemCodex
|
|
||||||
// The existing ItemCodex must be rewritten to clear out obsolete records
|
|
||||||
|
|
||||||
// We're assuming the dynamic item generated by players does exist in the world, and it's recorded
|
|
||||||
// into the world's dynamicToStaticTable, therefore every item recorded into the world's dynamicToStaticTable
|
|
||||||
// can be found in this world without need to look up the players
|
|
||||||
ingame.world.dynamicToStaticTable.clear()
|
|
||||||
ingame.world.dynamicItemInventory.clear()
|
|
||||||
actorsList.filterIsInstance<Pocketed>().forEach { actor ->
|
|
||||||
actor.inventory.forEach { (itemid, _) ->
|
|
||||||
|
|
||||||
printdbg(this, "World side dynamicitem: $itemid contained in $actor")
|
|
||||||
|
|
||||||
if (itemid.startsWith("$PREFIX_DYNAMICITEM:")) {
|
|
||||||
ingame.world.dynamicToStaticTable[itemid] = ItemCodex.dynamicToStaticID(itemid)
|
|
||||||
ingame.world.dynamicItemInventory[itemid] = ItemCodex[itemid]!!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
actorsList.filterIsInstance<FixtureBase>().forEach { fixture ->
|
|
||||||
fixture.inventory?.forEach { (itemid, _) ->
|
|
||||||
|
|
||||||
printdbg(this, "World side dynamicitem: $itemid contained in $fixture")
|
|
||||||
|
|
||||||
if (itemid.startsWith("$PREFIX_DYNAMICITEM:")) {
|
|
||||||
ingame.world.dynamicToStaticTable[itemid] = ItemCodex.dynamicToStaticID(itemid)
|
|
||||||
ingame.world.dynamicItemInventory[itemid] = ItemCodex[itemid]!!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (hasThumbnail) {
|
|
||||||
PixmapIO2._writeTGA(gzout, IngameRenderer.fboRGBexport, true, true)
|
|
||||||
IngameRenderer.fboRGBexport.dispose()
|
|
||||||
|
|
||||||
val thumbContent = EntryFile(tgaout.toByteArray64())
|
|
||||||
val thumb = DiskEntry(THUMBNAIL, ROOT, creation_t, time_t, thumbContent)
|
|
||||||
addFile(disk, thumb)
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteSavegame.saveProgress += 1f
|
|
||||||
|
|
||||||
// Write World //
|
|
||||||
|
|
||||||
val worldMeta = EntryFile(WriteWorld.encodeToByteArray64(ingame, time_t, actorsList, playersList))
|
|
||||||
val world = DiskEntry(SAVEGAMEINFO, ROOT, creation_t, time_t, worldMeta)
|
|
||||||
addFile(disk, world)
|
|
||||||
|
|
||||||
WriteSavegame.saveProgress += 1f
|
|
||||||
|
|
||||||
|
|
||||||
for (layer in layers.indices) {
|
|
||||||
for (cx in 0 until cw) {
|
|
||||||
for (cy in 0 until ch) {
|
|
||||||
val chunkNumber = LandUtil.chunkXYtoChunkNum(ingame.world, cx, cy).toLong()
|
|
||||||
|
|
||||||
// Echo("Writing chunks... ${(cw*ch*layer) + chunkNumber + 1}/${cw*ch*layers.size}")
|
|
||||||
|
|
||||||
val chunkBytes = WriteWorld.encodeChunk(layers[layer]!!, cx, cy)
|
|
||||||
val entryID = 0x1_0000_0000L or layer.toLong().shl(24) or chunkNumber
|
|
||||||
|
|
||||||
val entryContent = EntryFile(chunkBytes)
|
|
||||||
val entry = DiskEntry(entryID, ROOT, creation_t, time_t, entryContent)
|
|
||||||
// "W1L0-92,15"
|
|
||||||
addFile(disk, entry)
|
|
||||||
|
|
||||||
WriteSavegame.saveProgress += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Write Actors //
|
|
||||||
actorsList.forEachIndexed { count, it ->
|
|
||||||
// Echo("Writing actors... ${count+1}/${actorsList.size}")
|
|
||||||
|
|
||||||
val actorContent = EntryFile(WriteActor.encodeToByteArray64(it))
|
|
||||||
val actor = DiskEntry(it.referenceID.toLong(), ROOT, creation_t, time_t, actorContent)
|
|
||||||
addFile(disk, actor)
|
|
||||||
|
|
||||||
WriteSavegame.saveProgress += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// write loadorder //
|
|
||||||
val loadOrderBa64Writer = ByteArray64Writer(Common.CHARSET)
|
|
||||||
loadOrderBa64Writer.write(ModMgr.loadOrder.joinToString("\n"))
|
|
||||||
loadOrderBa64Writer.flush(); loadOrderBa64Writer.close()
|
|
||||||
val loadOrderText = loadOrderBa64Writer.toByteArray64()
|
|
||||||
val loadOrderContents = EntryFile(loadOrderText)
|
|
||||||
addFile(disk, DiskEntry(LOADORDER, ROOT, creation_t, time_t, loadOrderContents))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Echo("Writing file to disk...")
|
|
||||||
|
|
||||||
disk.entries[0]!!.modificationDate = time_t
|
|
||||||
// entry zero MUST NOT be used to get lastPlayDate, but we'll update it anyway
|
|
||||||
// use entry -1 for that purpose!
|
|
||||||
disk.capacity = 0
|
|
||||||
VDUtil.dumpToRealMachine(disk, outFile)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
printdbg(this, "Game saved with size of ${outFile.length()} bytes")
|
|
||||||
|
|
||||||
|
|
||||||
if (hasThumbnail) IngameRenderer.fboRGBexportedLatch = false
|
|
||||||
WriteSavegame.savingStatus = 255
|
|
||||||
|
|
||||||
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function called means the "Avatar" was not externally created and thus has no sprite-bodypart-name-to-entry-number-map
|
|
||||||
*
|
|
||||||
* Created by minjaesong on 2021-10-08
|
|
||||||
*/
|
|
||||||
class PlayerSavingThread(
|
|
||||||
val time_t: Long,
|
|
||||||
val disk: VirtualDisk,
|
|
||||||
val outFile: File,
|
|
||||||
val ingame: TerrarumIngame,
|
|
||||||
val hasThumbnail: Boolean,
|
|
||||||
val isAuto: Boolean,
|
|
||||||
val callback: () -> Unit,
|
|
||||||
val errorHandler: (Throwable) -> Unit
|
|
||||||
) : SavingThread(errorHandler) {
|
|
||||||
|
|
||||||
override fun save() {
|
|
||||||
disk.saveMode = 2 * isAuto.toInt() // no quick
|
|
||||||
disk.saveKind = VDSaveKind.PLAYER_DATA
|
|
||||||
disk.capacity = 0L
|
|
||||||
|
|
||||||
WriteSavegame.saveProgress = 0f
|
|
||||||
|
|
||||||
printdbg(this, "Writing The Player...")
|
|
||||||
WritePlayer(ingame.actorGamer, disk, ingame, time_t)
|
|
||||||
disk.entries[0]!!.modificationDate = time_t
|
|
||||||
VDUtil.dumpToRealMachine(disk, outFile)
|
|
||||||
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package net.torvald.terrarum.modulebasegame.serialise
|
||||||
|
|
||||||
|
import net.torvald.gdx.graphics.PixmapIO2
|
||||||
|
import net.torvald.terrarum.App
|
||||||
|
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
||||||
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
|
import net.torvald.terrarum.savegame.*
|
||||||
|
import net.torvald.terrarum.toInt
|
||||||
|
import java.io.File
|
||||||
|
import java.util.zip.GZIPOutputStream
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function called means the "Avatar" was not externally created and thus has no sprite-bodypart-name-to-entry-number-map
|
||||||
|
*
|
||||||
|
* Created by minjaesong on 2021-10-08
|
||||||
|
*/
|
||||||
|
class PlayerSavingThread(
|
||||||
|
val time_t: Long,
|
||||||
|
val disk: VirtualDisk,
|
||||||
|
val outFile: File,
|
||||||
|
val ingame: TerrarumIngame,
|
||||||
|
val isAuto: Boolean,
|
||||||
|
val callback: () -> Unit,
|
||||||
|
val errorHandler: (Throwable) -> Unit
|
||||||
|
) : SavingThread(errorHandler) {
|
||||||
|
/**
|
||||||
|
* Will happily overwrite existing entry
|
||||||
|
*/
|
||||||
|
private fun addFile(disk: VirtualDisk, file: DiskEntry) {
|
||||||
|
disk.entries[file.entryID] = file
|
||||||
|
file.parentEntryID = 0
|
||||||
|
val dir = VDUtil.getAsDirectory(disk, 0)
|
||||||
|
if (!dir.contains(file.entryID)) dir.add(file.entryID)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun save() {
|
||||||
|
App.printdbg(this, "outFile: ${outFile.path}")
|
||||||
|
|
||||||
|
disk.saveMode = 2 * isAuto.toInt() // no quick
|
||||||
|
disk.saveKind = VDSaveKind.PLAYER_DATA
|
||||||
|
disk.capacity = 0L
|
||||||
|
|
||||||
|
WriteSavegame.saveProgress = 0f
|
||||||
|
|
||||||
|
// wait for screencap
|
||||||
|
var emergencyStopCnt = 0
|
||||||
|
while (IngameRenderer.screencapBusy) {
|
||||||
|
// printdbg(this, "spinning for screencap to be taken")
|
||||||
|
Thread.sleep(4L)
|
||||||
|
emergencyStopCnt += 1
|
||||||
|
if (emergencyStopCnt >= SCREENCAP_WAIT_TRY_MAX) throw InterruptedException("Waiting screencap to be taken for too long")
|
||||||
|
}
|
||||||
|
|
||||||
|
// write screencap
|
||||||
|
val tgaout = ByteArray64GrowableOutputStream()
|
||||||
|
val gzout = GZIPOutputStream(tgaout)
|
||||||
|
PixmapIO2._writeTGA(gzout, IngameRenderer.fboRGBexport, true, true)
|
||||||
|
IngameRenderer.fboRGBexport.dispose()
|
||||||
|
// App.disposables.add(IngameRenderer.fboRGBexport)
|
||||||
|
val thumbContent = EntryFile(tgaout.toByteArray64())
|
||||||
|
val thumb =
|
||||||
|
DiskEntry(VDFileID.PLAYER_SCREENSHOT, VDFileID.ROOT, ingame.world.creationTime, time_t, thumbContent)
|
||||||
|
addFile(disk, thumb)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
App.printdbg(this, "Writing The Player...")
|
||||||
|
WritePlayer(ingame.actorGamer, disk, ingame, time_t)
|
||||||
|
disk.entries[0]!!.modificationDate = time_t
|
||||||
|
VDUtil.dumpToRealMachine(disk, outFile)
|
||||||
|
|
||||||
|
|
||||||
|
// IngameRenderer.screencapBusy = false
|
||||||
|
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,6 @@ class QuickSingleplayerWorldSavingThread(
|
|||||||
val disk: VirtualDisk,
|
val disk: VirtualDisk,
|
||||||
val outFile: File,
|
val outFile: File,
|
||||||
val ingame: TerrarumIngame,
|
val ingame: TerrarumIngame,
|
||||||
val hasThumbnail: Boolean,
|
|
||||||
val isAuto: Boolean,
|
val isAuto: Boolean,
|
||||||
val callback: () -> Unit,
|
val callback: () -> Unit,
|
||||||
val errorHandler: (Throwable) -> Unit
|
val errorHandler: (Throwable) -> Unit
|
||||||
@@ -46,12 +45,17 @@ class QuickSingleplayerWorldSavingThread(
|
|||||||
|
|
||||||
|
|
||||||
override fun save() {
|
override fun save() {
|
||||||
|
printdbg(this, "outFile: ${outFile.path}")
|
||||||
|
|
||||||
val skimmer = DiskSkimmer(outFile)
|
val skimmer = DiskSkimmer(outFile)
|
||||||
|
|
||||||
if (hasThumbnail) {
|
// wait for screencap
|
||||||
while (!IngameRenderer.fboRGBexportedLatch) {
|
var emergencyStopCnt = 0
|
||||||
Thread.sleep(1L)
|
while (IngameRenderer.screencapBusy) {
|
||||||
}
|
// printdbg(this, "spinning for screencap to be taken")
|
||||||
|
Thread.sleep(4L)
|
||||||
|
emergencyStopCnt += 1
|
||||||
|
if (emergencyStopCnt >= SCREENCAP_WAIT_TRY_MAX) throw InterruptedException("Waiting screencap to be taken for too long")
|
||||||
}
|
}
|
||||||
|
|
||||||
val allTheActors = ingame.actorContainerActive.cloneToList() + ingame.actorContainerInactive.cloneToList()
|
val allTheActors = ingame.actorContainerActive.cloneToList() + ingame.actorContainerInactive.cloneToList()
|
||||||
@@ -76,14 +80,14 @@ class QuickSingleplayerWorldSavingThread(
|
|||||||
val creation_t = ingame.world.creationTime
|
val creation_t = ingame.world.creationTime
|
||||||
|
|
||||||
|
|
||||||
if (hasThumbnail) {
|
PixmapIO2._writeTGA(gzout, IngameRenderer.fboRGBexport, true, true)
|
||||||
PixmapIO2._writeTGA(gzout, IngameRenderer.fboRGBexport, true, true)
|
IngameRenderer.fboRGBexport.dispose()
|
||||||
IngameRenderer.fboRGBexport.dispose()
|
|
||||||
|
val thumbContent = EntryFile(tgaout.toByteArray64())
|
||||||
|
val thumb = DiskEntry(THUMBNAIL, ROOT, creation_t, time_t, thumbContent)
|
||||||
|
addFile(disk, thumb)
|
||||||
|
|
||||||
|
|
||||||
val thumbContent = EntryFile(tgaout.toByteArray64())
|
|
||||||
val thumb = DiskEntry(THUMBNAIL, ROOT, creation_t, time_t, thumbContent)
|
|
||||||
addFile(disk, thumb)
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteSavegame.saveProgress += 1f
|
WriteSavegame.saveProgress += 1f
|
||||||
|
|
||||||
@@ -150,7 +154,7 @@ class QuickSingleplayerWorldSavingThread(
|
|||||||
printdbg(this, "Game saved with size of ${outFile.length()} bytes")
|
printdbg(this, "Game saved with size of ${outFile.length()} bytes")
|
||||||
|
|
||||||
|
|
||||||
if (hasThumbnail) IngameRenderer.fboRGBexportedLatch = false
|
// IngameRenderer.screencapBusy = false
|
||||||
WriteSavegame.savingStatus = 255
|
WriteSavegame.savingStatus = 255
|
||||||
ingame.clearModifiedChunks()
|
ingame.clearModifiedChunks()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,189 @@
|
|||||||
|
package net.torvald.terrarum.modulebasegame.serialise
|
||||||
|
|
||||||
|
import net.torvald.gdx.graphics.PixmapIO2
|
||||||
|
import net.torvald.terrarum.*
|
||||||
|
import net.torvald.terrarum.modulebasegame.IngameRenderer
|
||||||
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
|
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase
|
||||||
|
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||||
|
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
|
||||||
|
import net.torvald.terrarum.realestate.LandUtil
|
||||||
|
import net.torvald.terrarum.savegame.*
|
||||||
|
import net.torvald.terrarum.serialise.Common
|
||||||
|
import java.io.File
|
||||||
|
import java.util.zip.GZIPOutputStream
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2021-09-14.
|
||||||
|
*/
|
||||||
|
class WorldSavingThread(
|
||||||
|
val time_t: Long,
|
||||||
|
val disk: VirtualDisk,
|
||||||
|
val outFile: File,
|
||||||
|
val ingame: TerrarumIngame,
|
||||||
|
val isAuto: Boolean,
|
||||||
|
val callback: () -> Unit,
|
||||||
|
val errorHandler: (Throwable) -> Unit
|
||||||
|
) : SavingThread(errorHandler) {
|
||||||
|
/**
|
||||||
|
* Will happily overwrite existing entry
|
||||||
|
*/
|
||||||
|
private fun addFile(disk: VirtualDisk, file: DiskEntry) {
|
||||||
|
disk.entries[file.entryID] = file
|
||||||
|
file.parentEntryID = 0
|
||||||
|
val dir = VDUtil.getAsDirectory(disk, 0)
|
||||||
|
if (!dir.contains(file.entryID)) dir.add(file.entryID)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun save() {
|
||||||
|
App.printdbg(this, "outFile: ${outFile.path}")
|
||||||
|
|
||||||
|
disk.saveMode = 2 * isAuto.toInt() // no quick
|
||||||
|
disk.saveKind = VDSaveKind.WORLD_DATA
|
||||||
|
|
||||||
|
// wait for screencap
|
||||||
|
var emergencyStopCnt = 0
|
||||||
|
while (IngameRenderer.screencapBusy) {
|
||||||
|
// printdbg(this, "spinning for screencap to be taken")
|
||||||
|
Thread.sleep(4L)
|
||||||
|
emergencyStopCnt += 1
|
||||||
|
if (emergencyStopCnt >= SCREENCAP_WAIT_TRY_MAX) throw InterruptedException("Waiting screencap to be taken for too long")
|
||||||
|
}
|
||||||
|
|
||||||
|
val allTheActors = ingame.actorContainerActive.cloneToList() + ingame.actorContainerInactive.cloneToList()
|
||||||
|
|
||||||
|
val playersList: List<IngamePlayer> = allTheActors.filterIsInstance<IngamePlayer>()
|
||||||
|
val actorsList = allTheActors.filter { WriteWorld.actorAcceptable(it) }
|
||||||
|
val layers = intArrayOf(0,1).map { ingame.world.getLayer(it) }
|
||||||
|
val cw = ingame.world.width / LandUtil.CHUNK_W
|
||||||
|
val ch = ingame.world.height / LandUtil.CHUNK_H
|
||||||
|
|
||||||
|
WriteSavegame.saveProgress = 0f
|
||||||
|
WriteSavegame.saveProgressMax = 3f + (cw * ch * layers.size) + actorsList.size
|
||||||
|
|
||||||
|
|
||||||
|
val tgaout = ByteArray64GrowableOutputStream()
|
||||||
|
val gzout = GZIPOutputStream(tgaout)
|
||||||
|
|
||||||
|
App.printdbg(this, "Writing metadata...")
|
||||||
|
|
||||||
|
val creation_t = ingame.world.creationTime
|
||||||
|
|
||||||
|
|
||||||
|
// Write subset of Ingame.ItemCodex
|
||||||
|
// The existing ItemCodex must be rewritten to clear out obsolete records
|
||||||
|
|
||||||
|
// We're assuming the dynamic item generated by players does exist in the world, and it's recorded
|
||||||
|
// into the world's dynamicToStaticTable, therefore every item recorded into the world's dynamicToStaticTable
|
||||||
|
// can be found in this world without need to look up the players
|
||||||
|
ingame.world.dynamicToStaticTable.clear()
|
||||||
|
ingame.world.dynamicItemInventory.clear()
|
||||||
|
actorsList.filterIsInstance<Pocketed>().forEach { actor ->
|
||||||
|
actor.inventory.forEach { (itemid, _) ->
|
||||||
|
|
||||||
|
App.printdbg(this, "World side dynamicitem: $itemid contained in $actor")
|
||||||
|
|
||||||
|
if (itemid.startsWith("${ReferencingRanges.PREFIX_DYNAMICITEM}:")) {
|
||||||
|
ingame.world.dynamicToStaticTable[itemid] = ItemCodex.dynamicToStaticID(itemid)
|
||||||
|
ingame.world.dynamicItemInventory[itemid] = ItemCodex[itemid]!!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
actorsList.filterIsInstance<FixtureBase>().forEach { fixture ->
|
||||||
|
fixture.inventory?.forEach { (itemid, _) ->
|
||||||
|
|
||||||
|
App.printdbg(this, "World side dynamicitem: $itemid contained in $fixture")
|
||||||
|
|
||||||
|
if (itemid.startsWith("${ReferencingRanges.PREFIX_DYNAMICITEM}:")) {
|
||||||
|
ingame.world.dynamicToStaticTable[itemid] = ItemCodex.dynamicToStaticID(itemid)
|
||||||
|
ingame.world.dynamicItemInventory[itemid] = ItemCodex[itemid]!!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PixmapIO2._writeTGA(gzout, IngameRenderer.fboRGBexport, true, true)
|
||||||
|
IngameRenderer.fboRGBexport.dispose()
|
||||||
|
|
||||||
|
val thumbContent = EntryFile(tgaout.toByteArray64())
|
||||||
|
val thumb = DiskEntry(VDFileID.THUMBNAIL, VDFileID.ROOT, creation_t, time_t, thumbContent)
|
||||||
|
addFile(disk, thumb)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
WriteSavegame.saveProgress += 1f
|
||||||
|
|
||||||
|
// Write World //
|
||||||
|
|
||||||
|
val worldMeta = EntryFile(WriteWorld.encodeToByteArray64(ingame, time_t, actorsList, playersList))
|
||||||
|
val world = DiskEntry(VDFileID.SAVEGAMEINFO, VDFileID.ROOT, creation_t, time_t, worldMeta)
|
||||||
|
addFile(disk, world)
|
||||||
|
|
||||||
|
WriteSavegame.saveProgress += 1f
|
||||||
|
|
||||||
|
|
||||||
|
for (layer in layers.indices) {
|
||||||
|
for (cx in 0 until cw) {
|
||||||
|
for (cy in 0 until ch) {
|
||||||
|
val chunkNumber = LandUtil.chunkXYtoChunkNum(ingame.world, cx, cy).toLong()
|
||||||
|
|
||||||
|
// Echo("Writing chunks... ${(cw*ch*layer) + chunkNumber + 1}/${cw*ch*layers.size}")
|
||||||
|
|
||||||
|
val chunkBytes = WriteWorld.encodeChunk(layers[layer]!!, cx, cy)
|
||||||
|
val entryID = 0x1_0000_0000L or layer.toLong().shl(24) or chunkNumber
|
||||||
|
|
||||||
|
val entryContent = EntryFile(chunkBytes)
|
||||||
|
val entry = DiskEntry(entryID, VDFileID.ROOT, creation_t, time_t, entryContent)
|
||||||
|
// "W1L0-92,15"
|
||||||
|
addFile(disk, entry)
|
||||||
|
|
||||||
|
WriteSavegame.saveProgress += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Write Actors //
|
||||||
|
actorsList.forEachIndexed { count, it ->
|
||||||
|
// Echo("Writing actors... ${count+1}/${actorsList.size}")
|
||||||
|
|
||||||
|
val actorContent = EntryFile(WriteActor.encodeToByteArray64(it))
|
||||||
|
val actor = DiskEntry(it.referenceID.toLong(), VDFileID.ROOT, creation_t, time_t, actorContent)
|
||||||
|
addFile(disk, actor)
|
||||||
|
|
||||||
|
WriteSavegame.saveProgress += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// write loadorder //
|
||||||
|
val loadOrderBa64Writer = ByteArray64Writer(Common.CHARSET)
|
||||||
|
loadOrderBa64Writer.write(ModMgr.loadOrder.joinToString("\n"))
|
||||||
|
loadOrderBa64Writer.flush(); loadOrderBa64Writer.close()
|
||||||
|
val loadOrderText = loadOrderBa64Writer.toByteArray64()
|
||||||
|
val loadOrderContents = EntryFile(loadOrderText)
|
||||||
|
addFile(disk, DiskEntry(VDFileID.LOADORDER, VDFileID.ROOT, creation_t, time_t, loadOrderContents))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Echo("Writing file to disk...")
|
||||||
|
|
||||||
|
disk.entries[0]!!.modificationDate = time_t
|
||||||
|
// entry zero MUST NOT be used to get lastPlayDate, but we'll update it anyway
|
||||||
|
// use entry -1 for that purpose!
|
||||||
|
disk.capacity = 0
|
||||||
|
VDUtil.dumpToRealMachine(disk, outFile)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
App.printdbg(this, "Game saved with size of ${outFile.length()} bytes")
|
||||||
|
|
||||||
|
|
||||||
|
// IngameRenderer.screencapBusy = false
|
||||||
|
WriteSavegame.savingStatus = 255
|
||||||
|
|
||||||
|
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -151,8 +151,16 @@ object ReadPlayer {
|
|||||||
object ReadActor {
|
object ReadActor {
|
||||||
|
|
||||||
operator fun invoke(disk: SimpleFileSystem, dataStream: Reader): Actor =
|
operator fun invoke(disk: SimpleFileSystem, dataStream: Reader): Actor =
|
||||||
Common.jsoner.fromJson<Actor?>(null, dataStream).also {
|
try {
|
||||||
fillInDetails(disk, it)
|
Common.jsoner.fromJson<Actor?>(null, dataStream).also {
|
||||||
|
fillInDetails(disk, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e: ClassCastException) {
|
||||||
|
System.err.println(e.message)
|
||||||
|
System.err.println("The JSON:")
|
||||||
|
System.err.println(dataStream.readText())
|
||||||
|
throw e
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fillInDetails(disk: SimpleFileSystem, actor: Actor) {
|
private fun fillInDetails(disk: SimpleFileSystem, actor: Actor) {
|
||||||
|
|||||||
@@ -36,43 +36,45 @@ object WriteSavegame {
|
|||||||
@Volatile var saveProgress = 0f
|
@Volatile var saveProgress = 0f
|
||||||
@Volatile var saveProgressMax = 1f
|
@Volatile var saveProgressMax = 1f
|
||||||
|
|
||||||
private fun getSaveThread(time_t: Long, mode: SaveMode, disk: VirtualDisk, outFile: File, ingame: TerrarumIngame, hasThumbnail: Boolean, isAuto: Boolean, errorHandler: (Throwable) -> Unit, callback: () -> Unit) = when (mode) {
|
private fun getSaveThread(time_t: Long, mode: SaveMode, disk: VirtualDisk, outFile: File, ingame: TerrarumIngame, isAuto: Boolean, errorHandler: (Throwable) -> Unit, callback: () -> Unit) = when (mode) {
|
||||||
SaveMode.WORLD -> WorldSavingThread(time_t, disk, outFile, ingame, hasThumbnail, isAuto, callback, errorHandler)
|
SaveMode.WORLD -> WorldSavingThread(time_t, disk, outFile, ingame, isAuto, callback, errorHandler)
|
||||||
SaveMode.PLAYER -> PlayerSavingThread(time_t, disk, outFile, ingame, hasThumbnail, isAuto, callback, errorHandler)
|
SaveMode.PLAYER -> PlayerSavingThread(time_t, disk, outFile, ingame, isAuto, callback, errorHandler)
|
||||||
SaveMode.QUICK_WORLD -> QuickSingleplayerWorldSavingThread(time_t, disk, outFile, ingame, hasThumbnail, isAuto, callback, errorHandler)
|
SaveMode.QUICK_WORLD -> QuickSingleplayerWorldSavingThread(time_t, disk, outFile, ingame, isAuto, callback, errorHandler)
|
||||||
else -> throw IllegalArgumentException("$mode")
|
else -> throw IllegalArgumentException("$mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun installScreencap() {
|
||||||
|
IngameRenderer.screencapExportCallback = { fb ->
|
||||||
|
printdbg(this, "Generating thumbnail...")
|
||||||
|
|
||||||
|
val w = 960
|
||||||
|
val h = 640
|
||||||
|
|
||||||
|
val cx = /*1-*/(WorldCamera.x % 2)
|
||||||
|
val cy = /*1-*/(WorldCamera.y % 2)
|
||||||
|
|
||||||
|
val x = (fb.width - w) / 2 - cx // force the even-numbered position
|
||||||
|
val y = (fb.height - h) / 2 - cy // force the even-numbered position
|
||||||
|
|
||||||
|
val p = Pixmap.createFromFrameBuffer(x, y, w, h)
|
||||||
|
IngameRenderer.fboRGBexport = p
|
||||||
|
//PixmapIO2._writeTGA(gzout, p, true, true)
|
||||||
|
//p.dispose()
|
||||||
|
|
||||||
|
printdbg(this, "Done thumbnail generation")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
operator fun invoke(time_t: Long, mode: SaveMode, disk: VirtualDisk, outFile: File, ingame: TerrarumIngame, isAuto: Boolean, errorHandler: (Throwable) -> Unit, callback: () -> Unit) {
|
operator fun invoke(time_t: Long, mode: SaveMode, disk: VirtualDisk, outFile: File, ingame: TerrarumIngame, isAuto: Boolean, errorHandler: (Throwable) -> Unit, callback: () -> Unit) {
|
||||||
savingStatus = 0
|
savingStatus = 0
|
||||||
val hasThumbnail = (mode == SaveMode.WORLD || mode == SaveMode.QUICK_WORLD)
|
|
||||||
printdbg(this, "Save queued")
|
printdbg(this, "Save queued")
|
||||||
|
|
||||||
if (hasThumbnail) {
|
installScreencap()
|
||||||
IngameRenderer.screencapExportCallback = { fb ->
|
try { printdbg(this, "ScreencapExport installed: ${IngameRenderer.screencapExportCallback}") }
|
||||||
printdbg(this, "Generating thumbnail...")
|
catch (e: UninitializedPropertyAccessException) { printdbg(this, "ScreencapExport installed: no") }
|
||||||
|
IngameRenderer.requestScreencap()
|
||||||
|
|
||||||
val w = 960
|
val savingThread = Thread(getSaveThread(time_t, mode, disk, outFile, ingame, isAuto, errorHandler, callback), "TerrarumBasegameGameSaveThread")
|
||||||
val h = 640
|
|
||||||
|
|
||||||
val cx = /*1-*/(WorldCamera.x % 2)
|
|
||||||
val cy = /*1-*/(WorldCamera.y % 2)
|
|
||||||
|
|
||||||
val x = (fb.width - w) / 2 - cx // force the even-numbered position
|
|
||||||
val y = (fb.height - h) / 2 - cy // force the even-numbered position
|
|
||||||
|
|
||||||
val p = Pixmap.createFromFrameBuffer(x, y, w, h)
|
|
||||||
IngameRenderer.fboRGBexport = p
|
|
||||||
//PixmapIO2._writeTGA(gzout, p, true, true)
|
|
||||||
//p.dispose()
|
|
||||||
IngameRenderer.fboRGBexportedLatch = true
|
|
||||||
|
|
||||||
printdbg(this, "Done thumbnail generation")
|
|
||||||
}
|
|
||||||
IngameRenderer.screencapRequested = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val savingThread = Thread(getSaveThread(time_t, mode, disk, outFile, ingame, hasThumbnail, isAuto, errorHandler, callback), "TerrarumBasegameGameSaveThread")
|
|
||||||
savingThread.start()
|
savingThread.start()
|
||||||
|
|
||||||
// it is caller's job to keep the game paused or keep a "save in progress" ui up
|
// it is caller's job to keep the game paused or keep a "save in progress" ui up
|
||||||
@@ -81,12 +83,15 @@ object WriteSavegame {
|
|||||||
|
|
||||||
|
|
||||||
fun immediate(time_t: Long, mode: SaveMode, disk: VirtualDisk, outFile: File, ingame: TerrarumIngame, isAuto: Boolean, errorHandler: (Throwable) -> Unit, callback: () -> Unit) {
|
fun immediate(time_t: Long, mode: SaveMode, disk: VirtualDisk, outFile: File, ingame: TerrarumIngame, isAuto: Boolean, errorHandler: (Throwable) -> Unit, callback: () -> Unit) {
|
||||||
|
|
||||||
savingStatus = 0
|
savingStatus = 0
|
||||||
|
|
||||||
printdbg(this, "Immediate save fired")
|
printdbg(this, "Immediate save fired")
|
||||||
|
|
||||||
val savingThread = Thread(getSaveThread(time_t, mode, disk, outFile, ingame, false, isAuto, errorHandler, callback), "TerrarumBasegameGameSaveThread")
|
installScreencap()
|
||||||
|
try { printdbg(this, "ScreencapExport installed: ${IngameRenderer.screencapExportCallback}") }
|
||||||
|
catch (e: UninitializedPropertyAccessException) { printdbg(this, "ScreencapExport installed: no") }
|
||||||
|
IngameRenderer.requestScreencap()
|
||||||
|
|
||||||
|
val savingThread = Thread(getSaveThread(time_t, mode, disk, outFile, ingame, isAuto, errorHandler, callback), "TerrarumBasegameGameSaveThread")
|
||||||
savingThread.start()
|
savingThread.start()
|
||||||
|
|
||||||
// it is caller's job to keep the game paused or keep a "save in progress" ui up
|
// it is caller's job to keep the game paused or keep a "save in progress" ui up
|
||||||
@@ -126,7 +131,7 @@ object LoadSavegame {
|
|||||||
printdbg(this, "Player localhash: ${player.localHashStr}, hasSprite: ${player.sprite != null}")
|
printdbg(this, "Player localhash: ${player.localHashStr}, hasSprite: ${player.sprite != null}")
|
||||||
|
|
||||||
val currentWorldId = player.worldCurrentlyPlaying
|
val currentWorldId = player.worldCurrentlyPlaying
|
||||||
val worldDisk = worldDisk0 ?: App.savegameWorlds[currentWorldId]!!
|
val worldDisk = worldDisk0 ?: App.savegameWorlds[currentWorldId]!!.loadable()
|
||||||
val world = ReadWorld(ByteArray64Reader(worldDisk.getFile(SAVEGAMEINFO)!!.bytes, Common.CHARSET), worldDisk.diskFile)
|
val world = ReadWorld(ByteArray64Reader(worldDisk.getFile(SAVEGAMEINFO)!!.bytes, Common.CHARSET), worldDisk.diskFile)
|
||||||
|
|
||||||
world.layerTerrain = BlockLayer(world.width, world.height)
|
world.layerTerrain = BlockLayer(world.width, world.height)
|
||||||
|
|||||||
@@ -48,12 +48,9 @@ class Notification : UICanvas() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val drawColor = Color(1f, 1f, 1f, 1f)
|
|
||||||
|
|
||||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||||
blendNormalStraightAlpha(batch)
|
blendNormalStraightAlpha(batch)
|
||||||
drawColor.a = handler.opacity
|
fontCol.a = handler.opacity * OPACITY
|
||||||
fontCol.a = handler.opacity
|
|
||||||
|
|
||||||
val realTextWidth = 12 + if (message.size == 1)
|
val realTextWidth = 12 + if (message.size == 1)
|
||||||
App.fontGame.getWidth(message[0])
|
App.fontGame.getWidth(message[0])
|
||||||
@@ -63,12 +60,11 @@ class Notification : UICanvas() {
|
|||||||
|
|
||||||
// force the UI to the centre of the screen
|
// force the UI to the centre of the screen
|
||||||
this.posX = (App.scr.width - displayedTextWidth) / 2
|
this.posX = (App.scr.width - displayedTextWidth) / 2
|
||||||
|
|
||||||
val textHeight = message.size * App.fontGame.lineHeight
|
val textHeight = message.size * App.fontGame.lineHeight
|
||||||
|
|
||||||
batch.color = drawColor
|
|
||||||
|
|
||||||
Toolkit.drawBaloon(batch, 0f, -textHeight, displayedTextWidth.toFloat(), textHeight)
|
|
||||||
|
Toolkit.drawBaloon(batch, 0f, -textHeight, displayedTextWidth.toFloat(), textHeight, handler.opacity * OPACITY)
|
||||||
|
|
||||||
batch.color = fontCol
|
batch.color = fontCol
|
||||||
message.forEachIndexed { index, s ->
|
message.forEachIndexed { index, s ->
|
||||||
@@ -79,7 +75,6 @@ class Notification : UICanvas() {
|
|||||||
|
|
||||||
|
|
||||||
// dunno why, it doesn't work without this.
|
// dunno why, it doesn't work without this.
|
||||||
drawColor.a = 1f
|
|
||||||
fontCol.a = 1f
|
fontCol.a = 1f
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +106,7 @@ class Notification : UICanvas() {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// private int messagesShowingIndex = 0;
|
// private int messagesShowingIndex = 0;
|
||||||
val OPEN_CLOSE_TIME = 0.16f
|
const val OPEN_CLOSE_TIME = 0.16f
|
||||||
|
const val OPACITY = 0.9f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class UIBuildingMakerBlockChooser(val parent: BuildingMaker): UICanvas() {
|
|||||||
activeCol = Color.WHITE
|
activeCol = Color.WHITE
|
||||||
)
|
)
|
||||||
|
|
||||||
paletteItem.clickOnceListener = { _, _, _ ->
|
paletteItem.clickOnceListener = { _, _ ->
|
||||||
parent.setPencilColour(prop.id)
|
parent.setPencilColour(prop.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,11 +100,9 @@ class UIBuildingMakerPenMenu(val parent: BuildingMaker): UICanvas() {
|
|||||||
toolButtons.forEachIndexed { index, button ->
|
toolButtons.forEachIndexed { index, button ->
|
||||||
uiItems.add(button)
|
uiItems.add(button)
|
||||||
|
|
||||||
button.clickOnceListener = { _, _, b ->
|
button.clickOnceListener = { _, _ ->
|
||||||
if (b == App.getConfigInt("config_mouseprimary")) {
|
toolButtonsJob[index].invoke()
|
||||||
toolButtonsJob[index].invoke()
|
closeGracefully()
|
||||||
closeGracefully()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import net.torvald.terrarum.itemproperties.CraftingCodex
|
|||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory
|
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.InventoryPair
|
import net.torvald.terrarum.modulebasegame.gameactors.InventoryPair
|
||||||
import net.torvald.terrarum.modulebasegame.ui.*
|
|
||||||
import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryItemGrid.Companion.listGap
|
import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryItemGrid.Companion.listGap
|
||||||
import net.torvald.terrarum.ui.Toolkit
|
import net.torvald.terrarum.ui.Toolkit
|
||||||
import net.torvald.terrarum.ui.UICanvas
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
@@ -203,8 +202,8 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// make sure grid buttons for ingredients do nothing (even if they are hidden!)
|
// make sure grid buttons for ingredients do nothing (even if they are hidden!)
|
||||||
itemListIngredients.gridModeButtons[0].touchDownListener = { _,_,_,_ -> }
|
itemListIngredients.navRemoCon.listButtonListener = { _,_, -> }
|
||||||
itemListIngredients.gridModeButtons[1].touchDownListener = { _,_,_,_ -> }
|
itemListIngredients.navRemoCon.gridButtonListener = { _,_, -> }
|
||||||
itemListIngredients.isCompactMode = true
|
itemListIngredients.isCompactMode = true
|
||||||
itemListIngredients.setCustomHighlightRuleSub {
|
itemListIngredients.setCustomHighlightRuleSub {
|
||||||
it.item?.let { ingredient ->
|
it.item?.let { ingredient ->
|
||||||
@@ -252,8 +251,8 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
|
|||||||
} } }
|
} } }
|
||||||
)
|
)
|
||||||
// make grid mode buttons work together
|
// make grid mode buttons work together
|
||||||
// itemListPlayer.gridModeButtons[0].touchDownListener = { _,_,_,_ -> setCompact(false) }
|
// itemListPlayer.gridModeButtons[0].clickOnceListener = { _,_ -> setCompact(false) }
|
||||||
// itemListPlayer.gridModeButtons[1].touchDownListener = { _,_,_,_ -> setCompact(true) }
|
// itemListPlayer.gridModeButtons[1].clickOnceListener = { _,_ -> setCompact(true) }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -317,7 +316,7 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
buttonCraft.touchDownListener = { _,_,_,_ ->
|
buttonCraft.clickOnceListener = { _,_ ->
|
||||||
getPlayerInventory().let { player -> recipeClicked?.let { recipe ->
|
getPlayerInventory().let { player -> recipeClicked?.let { recipe ->
|
||||||
// check if player has enough amount of ingredients
|
// check if player has enough amount of ingredients
|
||||||
val itemCraftable = itemListIngredients.getInventory().itemList.all { (itm, qty) ->
|
val itemCraftable = itemListIngredients.getInventory().itemList.all { (itm, qty) ->
|
||||||
@@ -340,8 +339,8 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
|
|||||||
refreshCraftButtonStatus()
|
refreshCraftButtonStatus()
|
||||||
}
|
}
|
||||||
// make grid mode buttons work together
|
// make grid mode buttons work together
|
||||||
// itemListCraftable.gridModeButtons[0].touchDownListener = { _,_,_,_ -> setCompact(false) }
|
// itemListCraftable.gridModeButtons[0].clickOnceListener = { _,_ -> setCompact(false) }
|
||||||
// itemListCraftable.gridModeButtons[1].touchDownListener = { _,_,_,_ -> setCompact(true) }
|
// itemListCraftable.gridModeButtons[1].clickOnceListener = { _,_ -> setCompact(true) }
|
||||||
|
|
||||||
handler.allowESCtoClose = true
|
handler.allowESCtoClose = true
|
||||||
|
|
||||||
@@ -387,7 +386,7 @@ class UICrafting(val full: UIInventoryFull) : UICanvas(), HasInventory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buttonCraft.isActive = itemCraftable
|
buttonCraft.isEnabled = itemCraftable
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset whatever player has selected to null and bring UI to its initial state
|
// reset whatever player has selected to null and bring UI to its initial state
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import com.badlogic.gdx.graphics.Color
|
|||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
import net.torvald.terrarum.App
|
import net.torvald.terrarum.App
|
||||||
import net.torvald.terrarum.CommonResourcePool
|
import net.torvald.terrarum.CommonResourcePool
|
||||||
|
import net.torvald.terrarum.INGAME
|
||||||
import net.torvald.terrarum.ceilInt
|
import net.torvald.terrarum.ceilInt
|
||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.CELL_COL
|
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.CELL_COL
|
||||||
@@ -29,7 +30,7 @@ class UIGraphicsControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
|||||||
private val h1MarginBottom = 4
|
private val h1MarginBottom = 4
|
||||||
|
|
||||||
private val options = arrayOf(
|
private val options = arrayOf(
|
||||||
arrayOf("", { Lang["MENU_OPTIONS_PERFORMANCE"] }, "h1"),
|
arrayOf("", { Lang["CREDITS_VFX"] }, "h1"),
|
||||||
arrayOf("fx_dither", { Lang["MENU_OPTIONS_DITHER"] }, "toggle"),
|
arrayOf("fx_dither", { Lang["MENU_OPTIONS_DITHER"] }, "toggle"),
|
||||||
arrayOf("fx_backgroundblur", { Lang["MENU_OPTIONS_BLUR"] }, "toggle"),
|
arrayOf("fx_backgroundblur", { Lang["MENU_OPTIONS_BLUR"] }, "toggle"),
|
||||||
arrayOf("maxparticles", { Lang["MENU_OPTIONS_PARTICLES"] }, "spinner,256,1024,256"),
|
arrayOf("maxparticles", { Lang["MENU_OPTIONS_PARTICLES"] }, "spinner,256,1024,256"),
|
||||||
@@ -39,7 +40,7 @@ class UIGraphicsControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
|||||||
arrayOf("displayfps", { Lang["MENU_LABEL_FRAMESPERSEC"] }, "spinner,0,300,2"),
|
arrayOf("displayfps", { Lang["MENU_LABEL_FRAMESPERSEC"] }, "spinner,0,300,2"),
|
||||||
arrayOf("usevsync", { Lang["MENU_OPTIONS_VSYNC"] }, "toggle"),
|
arrayOf("usevsync", { Lang["MENU_OPTIONS_VSYNC"] }, "toggle"),
|
||||||
arrayOf("", { "(${Lang["MENU_LABEL_RESTART_REQUIRED"]})" }, "p"),
|
arrayOf("", { "(${Lang["MENU_LABEL_RESTART_REQUIRED"]})" }, "p"),
|
||||||
arrayOf("", { Lang["GAME_GENRE_MISC"] }, "h1"),
|
arrayOf("", { Lang["MENU_LABEL_STREAMING"] }, "h1"),
|
||||||
arrayOf("fx_streamerslayout", { Lang["MENU_OPTION_STREAMERS_LAYOUT"] }, "toggle"),
|
arrayOf("fx_streamerslayout", { Lang["MENU_OPTION_STREAMERS_LAYOUT"] }, "toggle"),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ class UIGraphicsControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
|||||||
}
|
}
|
||||||
else if (args.startsWith("toggle")) {
|
else if (args.startsWith("toggle")) {
|
||||||
UIItemToggleButton(this, x, y, spinnerWidth, App.getConfigBoolean(optionName)) to { it: UIItem, optionStr: String ->
|
UIItemToggleButton(this, x, y, spinnerWidth, App.getConfigBoolean(optionName)) to { it: UIItem, optionStr: String ->
|
||||||
(it as UIItemToggleButton).clickOnceListener = { _, _, _ ->
|
(it as UIItemToggleButton).clickOnceListener = { _, _ ->
|
||||||
it.toggle()
|
it.toggle()
|
||||||
App.setConfig(optionStr, it.getStatus())
|
App.setConfig(optionStr, it.getStatus())
|
||||||
}
|
}
|
||||||
@@ -109,11 +110,16 @@ class UIGraphicsControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
|||||||
UIItemSpinner(this, x, y, App.getConfigDouble(optionName), arg[1].toDouble(), arg[2].toDouble(), arg[3].toDouble(), spinnerWidth, numberToTextFunction = { "${((it as Double)*100).toInt()}%" }) to { it: UIItem, optionStr: String ->
|
UIItemSpinner(this, x, y, App.getConfigDouble(optionName), arg[1].toDouble(), arg[2].toDouble(), arg[3].toDouble(), spinnerWidth, numberToTextFunction = { "${((it as Double)*100).toInt()}%" }) to { it: UIItem, optionStr: String ->
|
||||||
(it as UIItemSpinner).selectionChangeListener = {
|
(it as UIItemSpinner).selectionChangeListener = {
|
||||||
App.setConfig(optionStr, it)
|
App.setConfig(optionStr, it)
|
||||||
} }
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (args.startsWith("typeinint")) {
|
else if (args.startsWith("typeinint")) {
|
||||||
// val arg = args.split(',') // args: none
|
// val arg = args.split(',') // args: none
|
||||||
UIItemTextLineInput(this, x, y, spinnerWidth, { "${App.getConfigInt(optionName)}" }, InputLenCap(4, InputLenCap.CharLenUnit.CODEPOINTS), { it.headkey in Input.Keys.NUM_0..Input.Keys.NUM_9 || it.headkey == Input.Keys.BACKSPACE }) to { it: UIItem, optionStr: String ->
|
UIItemTextLineInput(this, x, y, spinnerWidth,
|
||||||
|
defaultValue = { "${App.getConfigInt(optionName)}" },
|
||||||
|
maxLen = InputLenCap(4, InputLenCap.CharLenUnit.CODEPOINTS),
|
||||||
|
keyFilter = { it.headkey in Input.Keys.NUM_0..Input.Keys.NUM_9 || it.headkey == Input.Keys.BACKSPACE }
|
||||||
|
) to { it: UIItem, optionStr: String ->
|
||||||
(it as UIItemTextLineInput).textCommitListener = {
|
(it as UIItemTextLineInput).textCommitListener = {
|
||||||
App.setConfig(optionStr, it.toInt()) // HAXXX!!!
|
App.setConfig(optionStr, it.toInt()) // HAXXX!!!
|
||||||
}
|
}
|
||||||
@@ -122,7 +128,12 @@ class UIGraphicsControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
|||||||
else if (args.startsWith("typeinres")) {
|
else if (args.startsWith("typeinres")) {
|
||||||
val keyWidth = optionName.substringBefore(',')
|
val keyWidth = optionName.substringBefore(',')
|
||||||
val keyHeight = optionName.substringAfter(',')
|
val keyHeight = optionName.substringAfter(',')
|
||||||
UIItemTextLineInput(this, x, y, spinnerWidth, { "${App.getConfigInt(keyWidth)}x${App.getConfigInt(keyHeight)}" }, InputLenCap(9, InputLenCap.CharLenUnit.CODEPOINTS), { it.headkey == Input.Keys.ENTER || it.headkey == Input.Keys.BACKSPACE || it.character?.matches(Regex("[0-9xX]")) == true }, UIItemTextButton.Companion.Alignment.CENTRE) to { it: UIItem, optionStr: String ->
|
UIItemTextLineInput(this, x, y, spinnerWidth,
|
||||||
|
defaultValue = { "${App.getConfigInt(keyWidth)}x${App.getConfigInt(keyHeight)}" },
|
||||||
|
maxLen = InputLenCap(9, InputLenCap.CharLenUnit.CODEPOINTS),
|
||||||
|
keyFilter = { it.headkey == Input.Keys.ENTER || it.headkey == Input.Keys.BACKSPACE || it.character?.matches(Regex("[0-9xX]")) == true },
|
||||||
|
alignment = UIItemTextButton.Companion.Alignment.CENTRE
|
||||||
|
) to { it: UIItem, optionStr: String ->
|
||||||
(it as UIItemTextLineInput).textCommitListener = { text ->
|
(it as UIItemTextLineInput).textCommitListener = { text ->
|
||||||
val text = text.lowercase()
|
val text = text.lowercase()
|
||||||
if (text.matches(Regex("""[0-9]+x[0-9]+"""))) {
|
if (text.matches(Regex("""[0-9]+x[0-9]+"""))) {
|
||||||
@@ -167,8 +178,11 @@ class UIGraphicsControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
|||||||
|
|
||||||
options.forEachIndexed { index, strings ->
|
options.forEachIndexed { index, strings ->
|
||||||
val mode = strings[2]
|
val mode = strings[2]
|
||||||
|
|
||||||
|
val font = if (mode == "h1") App.fontUITitle else App.fontGame
|
||||||
|
|
||||||
val label = (strings[1] as () -> String).invoke()
|
val label = (strings[1] as () -> String).invoke()
|
||||||
val labelWidth = App.fontGame.getWidth(label)
|
val labelWidth = font.getWidth(label)
|
||||||
batch.color = when (mode) {
|
batch.color = when (mode) {
|
||||||
"h1" -> Toolkit.Theme.COL_MOUSE_UP
|
"h1" -> Toolkit.Theme.COL_MOUSE_UP
|
||||||
"p" -> Color.LIGHT_GRAY
|
"p" -> Color.LIGHT_GRAY
|
||||||
@@ -180,7 +194,7 @@ class UIGraphicsControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
|||||||
else
|
else
|
||||||
drawX + width/2 - panelgap - labelWidth // right aligned at the middle of the panel, offsetted by panelgap
|
drawX + width/2 - panelgap - labelWidth // right aligned at the middle of the panel, offsetted by panelgap
|
||||||
|
|
||||||
App.fontGame.draw(batch, label, xpos.toFloat(), drawY + optionsYpos[index] - 2f)
|
font.draw(batch, label, xpos.toFloat(), drawY + optionsYpos[index] - 2f)
|
||||||
|
|
||||||
// draw hrule
|
// draw hrule
|
||||||
if (mode == "h1") {
|
if (mode == "h1") {
|
||||||
@@ -209,6 +223,14 @@ class UIGraphicsControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||||
|
return super.touchDown(screenX, screenY, pointer, button)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||||
|
return super.touchUp(screenX, screenY, pointer, button)
|
||||||
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,14 +110,14 @@ class UIIMEConfig(remoCon: UIRemoCon?) : UICanvas() {
|
|||||||
private val selDrawX = (Toolkit.drawWidth - selectorWidth) / 2
|
private val selDrawX = (Toolkit.drawWidth - selectorWidth) / 2
|
||||||
private val halfw = width / 2
|
private val halfw = width / 2
|
||||||
|
|
||||||
private val y1 = 400
|
// private val y1 = 400
|
||||||
private val y2 = y1 + 40
|
// private val y2 = y1 + 40
|
||||||
|
|
||||||
private val lowLayerCodes = IME.getAllLowLayers().sorted()
|
private val lowLayerCodes = IME.getAllLowLayers().sorted()
|
||||||
private val lowLayerNames = lowLayerCodes.map { { IME.getLowLayerByName(it).name } }
|
private val lowLayerNames = lowLayerCodes.map { { IME.getLowLayerByName(it).name } }
|
||||||
private val keyboardLayoutSelection = UIItemTextSelector(this,
|
private val keyboardLayoutSelection = UIItemTextSelector(this,
|
||||||
selDrawX + (halfselw - textSelWidth) / 2,
|
selDrawX + (halfselw - textSelWidth) / 2,
|
||||||
y2,
|
kby + 260,
|
||||||
lowLayerNames,
|
lowLayerNames,
|
||||||
lowLayerCodes.linearSearch { it == App.getConfigString("basekeyboardlayout") } ?: throw IME.LayoutNotFound(App.getConfigString("basekeyboardlayout")),
|
lowLayerCodes.linearSearch { it == App.getConfigString("basekeyboardlayout") } ?: throw IME.LayoutNotFound(App.getConfigString("basekeyboardlayout")),
|
||||||
textSelWidth
|
textSelWidth
|
||||||
@@ -127,8 +127,8 @@ class UIIMEConfig(remoCon: UIRemoCon?) : UICanvas() {
|
|||||||
private val imeCodes = listOf("none") + imeCodes0
|
private val imeCodes = listOf("none") + imeCodes0
|
||||||
private val imeNames = listOf({"$EMDASH"}) + imeCodes0.map { { IME.getHighLayerByName(it).name } }
|
private val imeNames = listOf({"$EMDASH"}) + imeCodes0.map { { IME.getHighLayerByName(it).name } }
|
||||||
private val imeSelection = UIItemTextSelector(this,
|
private val imeSelection = UIItemTextSelector(this,
|
||||||
selDrawX + halfselw + (halfselw - textSelWidth) / 2,
|
selDrawX + halfselw + (halfselw - textSelWidth) / 2,
|
||||||
y2,
|
kby + 260,
|
||||||
imeNames,
|
imeNames,
|
||||||
imeCodes.linearSearch { it == App.getConfigString("inputmethod") } ?: throw IME.LayoutNotFound(App.getConfigString("inputmethod")),
|
imeCodes.linearSearch { it == App.getConfigString("inputmethod") } ?: throw IME.LayoutNotFound(App.getConfigString("inputmethod")),
|
||||||
textSelWidth
|
textSelWidth
|
||||||
@@ -138,7 +138,7 @@ class UIIMEConfig(remoCon: UIRemoCon?) : UICanvas() {
|
|||||||
|
|
||||||
private val keyboardTestPanel = UIItemTextLineInput(this,
|
private val keyboardTestPanel = UIItemTextLineInput(this,
|
||||||
drawX + (width - 480) / 2 + 3,
|
drawX + (width - 480) / 2 + 3,
|
||||||
height - 40,
|
drawY + height - 120,
|
||||||
474
|
474
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -171,23 +171,23 @@ class UIIMEConfig(remoCon: UIRemoCon?) : UICanvas() {
|
|||||||
batch.color = Color.WHITE
|
batch.color = Color.WHITE
|
||||||
|
|
||||||
val txt1 = Lang["MENU_LABEL_KEYBOARD_LAYOUT"]; val tw1 = App.fontGame.getWidth(txt1)
|
val txt1 = Lang["MENU_LABEL_KEYBOARD_LAYOUT"]; val tw1 = App.fontGame.getWidth(txt1)
|
||||||
App.fontGame.draw(batch, txt1, selDrawX + (halfselw - tw1) / 2, y1)
|
App.fontGame.draw(batch, txt1, selDrawX + (halfselw - tw1) / 2, keyboardLayoutSelection.posY - 40)
|
||||||
|
|
||||||
val txt2 = Lang["MENU_LABEL_IME"]; val tw2 = App.fontGame.getWidth(txt2)
|
val txt2 = Lang["MENU_LABEL_IME"]; val tw2 = App.fontGame.getWidth(txt2)
|
||||||
App.fontGame.draw(batch, txt2, selDrawX + halfselw + (halfselw - tw2) / 2, y1)
|
App.fontGame.draw(batch, txt2, selDrawX + halfselw + (halfselw - tw2) / 2, keyboardLayoutSelection.posY - 40)
|
||||||
|
|
||||||
// title
|
// title
|
||||||
// todo show "Keyboard"/"Gamepad" accordingly
|
// todo show "Keyboard"/"Gamepad" accordingly
|
||||||
val title = Lang["MENU_CONTROLS_KEYBOARD"]
|
val title = Lang["MENU_CONTROLS_KEYBOARD"]
|
||||||
batch.color = Color.WHITE
|
batch.color = Color.WHITE
|
||||||
App.fontGame.draw(batch, title, drawX.toFloat() + (width - App.fontGame.getWidth(title)) / 2, drawY.toFloat())
|
App.fontUITitle.draw(batch, title, drawX.toFloat() + (width - App.fontUITitle.getWidth(title)) / 2, drawY.toFloat())
|
||||||
|
|
||||||
|
|
||||||
// button help for string input UI
|
// button help for string input UI
|
||||||
val help1 = "↓ ${Lang["MENU_LABEL_IME_TOGGLE"]}"
|
val help1 = "↓ ${Lang["MENU_LABEL_IME_TOGGLE"]}"
|
||||||
App.fontGame.draw(batch, help1, drawX + 10f, height - 40f - 28f)
|
App.fontGame.draw(batch, help1, drawX + 10f, keyboardTestPanel.posY - 28f)
|
||||||
val help2 = "${Lang["MENU_LABEL_PASTE_FROM_CLIPBOARD"]} ↑"
|
val help2 = "${Lang["MENU_LABEL_PASTE_FROM_CLIPBOARD"]} ↑"
|
||||||
App.fontGame.draw(batch, help2, drawX + keyboardTestPanel.width - 4f - App.fontGame.getWidth(help2), height - 40f + 30f)
|
App.fontGame.draw(batch, help2, drawX + keyboardTestPanel.width - 4f - App.fontGame.getWidth(help2), keyboardTestPanel.posY + 30f)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
|
|||||||
defaultSelection = null
|
defaultSelection = null
|
||||||
)
|
)
|
||||||
private val areYouSureMainMenuButtons = UIItemTextButtonList(
|
private val areYouSureMainMenuButtons = UIItemTextButtonList(
|
||||||
this, DEFAULT_LINE_HEIGHT, arrayOf("MENU_LABEL_QUIT_CONFIRM", "MENU_LABEL_QUIT", "MENU_LABEL_CANCEL"),
|
this, DEFAULT_LINE_HEIGHT, arrayOf("MENU_LABEL_QUIT_CONFIRM", "MENU_LABEL_UNSAVED_PROGRESSES_WILL_BE_LOST", "MENU_LABEL_QUIT", "MENU_LABEL_CANCEL"),
|
||||||
(width - gameMenuListWidth) / 2,
|
(width - gameMenuListWidth) / 2,
|
||||||
INVENTORY_CELLS_OFFSET_Y() + (INVENTORY_CELLS_UI_HEIGHT - (DEFAULT_LINE_HEIGHT * 3)) / 2,
|
INVENTORY_CELLS_OFFSET_Y() + (INVENTORY_CELLS_UI_HEIGHT - (DEFAULT_LINE_HEIGHT * 3)) / 2,
|
||||||
gameMenuListWidth, DEFAULT_LINE_HEIGHT * 3,
|
gameMenuListWidth, DEFAULT_LINE_HEIGHT * 3,
|
||||||
@@ -60,7 +60,12 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
|
|||||||
highlightBackCol = Color(0),
|
highlightBackCol = Color(0),
|
||||||
inactiveCol = Color.WHITE,
|
inactiveCol = Color.WHITE,
|
||||||
defaultSelection = null
|
defaultSelection = null
|
||||||
)
|
).also {
|
||||||
|
listOf(it.buttons[0], it.buttons[1]).forEach {
|
||||||
|
it.skipUpdate = true
|
||||||
|
it.isActive = false
|
||||||
|
}
|
||||||
|
}
|
||||||
/*private val areYouSureQuitButtons = UIItemTextButtonList(
|
/*private val areYouSureQuitButtons = UIItemTextButtonList(
|
||||||
this, DEFAULT_LINE_HEIGHT, arrayOf("MENU_LABEL_DESKTOP_QUESTION", "MENU_LABEL_DESKTOP", "MENU_LABEL_CANCEL"),
|
this, DEFAULT_LINE_HEIGHT, arrayOf("MENU_LABEL_DESKTOP_QUESTION", "MENU_LABEL_DESKTOP", "MENU_LABEL_CANCEL"),
|
||||||
(width - gameMenuListWidth) / 2,
|
(width - gameMenuListWidth) / 2,
|
||||||
@@ -105,11 +110,19 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
|
|||||||
full.unlockTransition()
|
full.unlockTransition()
|
||||||
}
|
}
|
||||||
|
|
||||||
val saveTime_t = App.getTIME_T()
|
val onSuccessful = {
|
||||||
|
// return to normal state
|
||||||
|
System.gc()
|
||||||
|
screen = 0
|
||||||
|
full.handler.unlockToggle()
|
||||||
|
full.unlockTransition()
|
||||||
|
(INGAME as TerrarumIngame).autosaveTimer = 0f
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*val saveTime_t = App.getTIME_T()
|
||||||
val playerSavefile = getPlayerSaveFiledesc(INGAME.playerSavefileName)
|
val playerSavefile = getPlayerSaveFiledesc(INGAME.playerSavefileName)
|
||||||
val worldSavefile = getWorldSaveFiledesc(INGAME.worldSavefileName)
|
val worldSavefile = getWorldSaveFiledesc(INGAME.worldSavefileName)
|
||||||
|
|
||||||
|
|
||||||
INGAME.makeSavegameBackupCopy(playerSavefile)
|
INGAME.makeSavegameBackupCopy(playerSavefile)
|
||||||
WriteSavegame(saveTime_t, WriteSavegame.SaveMode.PLAYER, INGAME.playerDisk, playerSavefile, INGAME as TerrarumIngame, false, onError) {
|
WriteSavegame(saveTime_t, WriteSavegame.SaveMode.PLAYER, INGAME.playerDisk, playerSavefile, INGAME as TerrarumIngame, false, onError) {
|
||||||
|
|
||||||
@@ -123,13 +136,12 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return to normal state
|
// return to normal state
|
||||||
System.gc()
|
onSuccessful()
|
||||||
screen = 0
|
|
||||||
full.handler.unlockToggle()
|
|
||||||
full.unlockTransition()
|
|
||||||
(INGAME as TerrarumIngame).autosaveTimer = 0f
|
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
INGAME.saveTheGame(onSuccessful, onError)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
1 -> {
|
1 -> {
|
||||||
@@ -148,11 +160,11 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
|
|||||||
}
|
}
|
||||||
areYouSureMainMenuButtons.selectionChangeListener = { _, new ->
|
areYouSureMainMenuButtons.selectionChangeListener = { _, new ->
|
||||||
when (new) {
|
when (new) {
|
||||||
1 -> {
|
2 -> {
|
||||||
areYouSureMainMenuButtons.deselect()
|
areYouSureMainMenuButtons.deselect()
|
||||||
App.setScreen(TitleScreen(App.batch))
|
App.setScreen(TitleScreen(App.batch))
|
||||||
}
|
}
|
||||||
2 -> {
|
3 -> {
|
||||||
screen = 0; areYouSureMainMenuButtons.deselect()
|
screen = 0; areYouSureMainMenuButtons.deselect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
|||||||
import net.torvald.terrarum.ui.Toolkit
|
import net.torvald.terrarum.ui.Toolkit
|
||||||
import net.torvald.terrarum.ui.UICanvas
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
import net.torvald.terrarum.ui.UIItemHorizontalFadeSlide
|
import net.torvald.terrarum.ui.UIItemHorizontalFadeSlide
|
||||||
|
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||||
import net.torvald.unicode.*
|
import net.torvald.unicode.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,8 +32,20 @@ class UIInventoryFull(
|
|||||||
override var height: Int = App.scr.height
|
override var height: Int = App.scr.height
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private var shapeRenderer: ShapeRenderer? = null
|
// private var shapeRenderer: ShapeRenderer? = null
|
||||||
|
|
||||||
|
private val backDropsLoaded = Array<Boolean>(16) { false }
|
||||||
|
private val backdrop01: TextureRegionPack
|
||||||
|
get() {
|
||||||
|
if (!backDropsLoaded[0]) {
|
||||||
|
CommonResourcePool.addToLoadingList("basegame.uibackdrop01") {
|
||||||
|
TextureRegionPack(ModMgr.getGdxFile("basegame", "gui/backdrop01.tga"), 2, 140)
|
||||||
|
}
|
||||||
|
CommonResourcePool.loadAll()
|
||||||
|
backDropsLoaded[0] = true
|
||||||
|
}
|
||||||
|
return CommonResourcePool.getAsTextureRegionPack("basegame.uibackdrop01")
|
||||||
|
}
|
||||||
|
|
||||||
val CELL_COL = Toolkit.Theme.COL_CELL_FILL
|
val CELL_COL = Toolkit.Theme.COL_CELL_FILL
|
||||||
|
|
||||||
@@ -58,6 +71,9 @@ class UIInventoryFull(
|
|||||||
val INVENTORY_CELLS_OFFSET_X = { 0 + (Toolkit.drawWidth - internalWidth) / 2 }
|
val INVENTORY_CELLS_OFFSET_X = { 0 + (Toolkit.drawWidth - internalWidth) / 2 }
|
||||||
val INVENTORY_CELLS_OFFSET_Y = { -YPOS_CORRECTION + 107 + (App.scr.height - internalHeight) / 2 }
|
val INVENTORY_CELLS_OFFSET_Y = { -YPOS_CORRECTION + 107 + (App.scr.height - internalHeight) / 2 }
|
||||||
|
|
||||||
|
fun getWidthOfCells(count: Int, cellWidth: Int = UIItemInventoryElemWide.height, gapWidth: Int = UIItemInventoryItemGrid.listGap) =
|
||||||
|
(cellWidth * count) + (gapWidth * (count - 1))
|
||||||
|
|
||||||
val catBarWidth = 330
|
val catBarWidth = 330
|
||||||
|
|
||||||
val gradStartCol = Color(0x404040_60)
|
val gradStartCol = Color(0x404040_60)
|
||||||
@@ -69,9 +85,11 @@ class UIInventoryFull(
|
|||||||
private val gsta = Color(gradStartCol)
|
private val gsta = Color(gradStartCol)
|
||||||
private val gend = Color(gradEndCol)
|
private val gend = Color(gradEndCol)
|
||||||
|
|
||||||
|
|
||||||
|
private val drawBackgroundColourBuffer = Color(1f,1f,1f,1f)
|
||||||
fun drawBackground(batch: SpriteBatch, opacity: Float) {
|
fun drawBackground(batch: SpriteBatch, opacity: Float) {
|
||||||
batch.end()
|
|
||||||
gdxBlendNormalStraightAlpha()
|
gdxBlendNormalStraightAlpha()
|
||||||
|
/*batch.end()
|
||||||
|
|
||||||
if (shapeRenderer == null) {
|
if (shapeRenderer == null) {
|
||||||
shapeRenderer = App.makeShapeRenderer()
|
shapeRenderer = App.makeShapeRenderer()
|
||||||
@@ -101,7 +119,23 @@ class UIInventoryFull(
|
|||||||
it.rect(0f, h, w, -(h - gradBottomEnd), gsta, gsta, gsta, gsta)
|
it.rect(0f, h, w, -(h - gradBottomEnd), gsta, gsta, gsta, gsta)
|
||||||
}
|
}
|
||||||
|
|
||||||
batch.begin()
|
batch.begin()*/
|
||||||
|
// drawBackgroundColourBuffer.a = opacity
|
||||||
|
batch.color = drawBackgroundColourBuffer
|
||||||
|
val w = App.scr.wf
|
||||||
|
val h = App.scr.hf
|
||||||
|
val gradTopStart = (-YPOS_CORRECTION + (App.scr.height - internalHeight).div(2).toFloat()) * App.scr.magn
|
||||||
|
|
||||||
|
val hTop = gradTopStart
|
||||||
|
val hTopRem = hTop - 64f
|
||||||
|
|
||||||
|
val hMid = h - 2 * (hTopRem + 140f)
|
||||||
|
batch.draw(backdrop01.get(0, 0), 0f, 0f, w, hTopRem)
|
||||||
|
batch.draw(backdrop01.get(0, 1), 0f, hTopRem, w, 140f)
|
||||||
|
batch.draw(backdrop01.get(0, 2), 0f, hTopRem + 140f, w, hMid)
|
||||||
|
batch.draw(backdrop01.get(0, 3), 0f, hTopRem + 140f + hMid, w, 140f)
|
||||||
|
batch.draw(backdrop01.get(0, 4), 0f, hTopRem + 280f + hMid, w, hTopRem)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,7 +315,7 @@ class UIInventoryFull(
|
|||||||
|
|
||||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||||
|
|
||||||
drawBackground(batch, handler.opacity)
|
drawBackground(batch, 1f)
|
||||||
|
|
||||||
// UI items
|
// UI items
|
||||||
catBar.render(batch, camera)
|
catBar.render(batch, camera)
|
||||||
|
|||||||
@@ -86,13 +86,18 @@ open class UIItemInventoryItemGrid(
|
|||||||
|
|
||||||
private val inventoryUI = parentUI
|
private val inventoryUI = parentUI
|
||||||
|
|
||||||
var itemPage = 0
|
var itemPage
|
||||||
set(value) {
|
set(value) {
|
||||||
field = if (itemPageCount == 0) 0 else (value).fmod(itemPageCount)
|
navRemoCon.itemPage = if (itemPageCount == 0) 0 else (value).fmod(itemPageCount)
|
||||||
rebuild(currentFilter)
|
rebuild(currentFilter)
|
||||||
}
|
}
|
||||||
var itemPageCount = 1 // TODO total size of current category / items.size
|
get() = navRemoCon.itemPage
|
||||||
protected set
|
|
||||||
|
var itemPageCount // TODO total size of current category / items.size
|
||||||
|
protected set(value) {
|
||||||
|
navRemoCon.itemPageCount = value
|
||||||
|
}
|
||||||
|
get() = navRemoCon.itemPageCount
|
||||||
|
|
||||||
var inventorySortList = ArrayList<InventoryPair>()
|
var inventorySortList = ArrayList<InventoryPair>()
|
||||||
protected var rebuildList = true
|
protected var rebuildList = true
|
||||||
@@ -140,35 +145,37 @@ open class UIItemInventoryItemGrid(
|
|||||||
|
|
||||||
fun createInvCellGenericTouchDownFun(listRebuildFun: () -> Unit): (GameItem?, Long, Int, Any?, UIItemInventoryCellBase) -> Unit {
|
fun createInvCellGenericTouchDownFun(listRebuildFun: () -> Unit): (GameItem?, Long, Int, Any?, UIItemInventoryCellBase) -> Unit {
|
||||||
return { item: GameItem?, amount: Long, button: Int, _, _ ->
|
return { item: GameItem?, amount: Long, button: Int, _, _ ->
|
||||||
if (item != null && Terrarum.ingame != null) {
|
if (button == App.getConfigInt("config_mouseprimary")) {
|
||||||
// equip da shit
|
if (item != null && Terrarum.ingame != null) {
|
||||||
val itemEquipSlot = item.equipPosition
|
// equip da shit
|
||||||
if (itemEquipSlot == GameItem.EquipPosition.NULL) {
|
val itemEquipSlot = item.equipPosition
|
||||||
TODO("Equip position is NULL, does this mean it's single-consume items like a potion? (from item: \"$item\" with itemID: ${item.originalID}/${item.dynamicID})")
|
if (itemEquipSlot == GameItem.EquipPosition.NULL) {
|
||||||
}
|
TODO("Equip position is NULL, does this mean it's single-consume items like a potion? (from item: \"$item\" with itemID: ${item.originalID}/${item.dynamicID})")
|
||||||
val player = (Terrarum.ingame!! as TerrarumIngame).actorNowPlaying
|
|
||||||
if (player != null) {
|
|
||||||
|
|
||||||
if (item != ItemCodex[player.inventory.itemEquipped.get(itemEquipSlot)]) { // if this item is unequipped, equip it
|
|
||||||
player.equipItem(item)
|
|
||||||
|
|
||||||
// also equip on the quickslot
|
|
||||||
player.actorValue.getAsInt(AVKey.__PLAYER_QUICKSLOTSEL)?.let {
|
|
||||||
player.inventory.setQuickslotItem(it, item.dynamicID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else { // if not, unequip it
|
val player = (Terrarum.ingame!! as TerrarumIngame).actorNowPlaying
|
||||||
player.unequipItem(item)
|
if (player != null) {
|
||||||
|
|
||||||
// also unequip on the quickslot
|
if (item != ItemCodex[player.inventory.itemEquipped.get(itemEquipSlot)]) { // if this item is unequipped, equip it
|
||||||
player.actorValue.getAsInt(AVKey.__PLAYER_QUICKSLOTSEL)?.let {
|
player.equipItem(item)
|
||||||
player.inventory.setQuickslotItem(it, null)
|
|
||||||
|
// also equip on the quickslot
|
||||||
|
player.actorValue.getAsInt(AVKey.__PLAYER_QUICKSLOTSEL)?.let {
|
||||||
|
player.inventory.setQuickslotItem(it, item.dynamicID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // if not, unequip it
|
||||||
|
player.unequipItem(item)
|
||||||
|
|
||||||
|
// also unequip on the quickslot
|
||||||
|
player.actorValue.getAsInt(AVKey.__PLAYER_QUICKSLOTSEL)?.let {
|
||||||
|
player.inventory.setQuickslotItem(it, null)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listRebuildFun()
|
||||||
}
|
}
|
||||||
|
|
||||||
listRebuildFun()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,50 +230,9 @@ open class UIItemInventoryItemGrid(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val iconPosX = if (drawScrollOnRightside)
|
private val iconPosX = if (drawScrollOnRightside)
|
||||||
posX + width + LIST_TO_CONTROL_GAP
|
posX + width
|
||||||
else
|
else
|
||||||
posX - LIST_TO_CONTROL_GAP - catBar.catIcons.tileW
|
posX - UIItemListNavBarVertical.LIST_TO_CONTROL_GAP - UIItemListNavBarVertical.WIDTH - 4
|
||||||
|
|
||||||
|
|
||||||
/** Long/compact mode buttons */
|
|
||||||
val gridModeButtons = Array<UIItemImageButton>(2) { index ->
|
|
||||||
UIItemImageButton(
|
|
||||||
parentUI,
|
|
||||||
catBar.catIcons.get(index + 14, 0),
|
|
||||||
backgroundCol = Color(0),
|
|
||||||
activeBackCol = Color(0),
|
|
||||||
highlightBackCol = Color(0),
|
|
||||||
activeBackBlendMode = BlendMode.NORMAL,
|
|
||||||
activeCol = Toolkit.Theme.COL_MOUSE_UP,
|
|
||||||
initialX = iconPosX,
|
|
||||||
initialY = getIconPosY(index),
|
|
||||||
highlightable = true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val scrollUpButton = UIItemImageButton(
|
|
||||||
parentUI,
|
|
||||||
catBar.catIcons.get(18, 0),
|
|
||||||
backgroundCol = Color(0),
|
|
||||||
activeBackCol = Color(0),
|
|
||||||
activeBackBlendMode = BlendMode.NORMAL,
|
|
||||||
activeCol = Toolkit.Theme.COL_MOUSE_UP,
|
|
||||||
initialX = iconPosX,
|
|
||||||
initialY = getIconPosY(2),
|
|
||||||
highlightable = false
|
|
||||||
)
|
|
||||||
|
|
||||||
private val scrollDownButton = UIItemImageButton(
|
|
||||||
parentUI,
|
|
||||||
catBar.catIcons.get(19, 0),
|
|
||||||
backgroundCol = Color(0),
|
|
||||||
activeBackCol = Color(0),
|
|
||||||
activeBackBlendMode = BlendMode.NORMAL,
|
|
||||||
activeCol = Toolkit.Theme.COL_MOUSE_UP,
|
|
||||||
initialX = iconPosX,
|
|
||||||
initialY = getIconPosY(3),
|
|
||||||
highlightable = false
|
|
||||||
)
|
|
||||||
|
|
||||||
fun setCustomHighlightRuleMain(predicate: ((UIItemInventoryCellBase) -> Boolean)?) {
|
fun setCustomHighlightRuleMain(predicate: ((UIItemInventoryCellBase) -> Boolean)?) {
|
||||||
itemGrid.forEach { it.customHighlightRuleMain = predicate }
|
itemGrid.forEach { it.customHighlightRuleMain = predicate }
|
||||||
@@ -282,63 +248,53 @@ open class UIItemInventoryItemGrid(
|
|||||||
itemPage = if (itemPageCount == 0) 0 else (itemPage + relativeAmount).fmod(itemPageCount)
|
itemPage = if (itemPageCount == 0) 0 else (itemPage + relativeAmount).fmod(itemPageCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val navRemoCon = UIItemListNavBarVertical(parentUI, iconPosX, posY + 8, height, true, if (isCompactMode) 1 else 0)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// initially highlight grid mode buttons
|
// initially highlight grid mode buttons
|
||||||
if (!hideSidebar) {
|
if (!hideSidebar) {
|
||||||
gridModeButtons[if (isCompactMode) 1 else 0].highlighted = true
|
navRemoCon.listButtonListener = { _, _ ->
|
||||||
|
|
||||||
|
|
||||||
gridModeButtons[0].touchDownListener = { _, _, _, _ ->
|
|
||||||
isCompactMode = false
|
isCompactMode = false
|
||||||
gridModeButtons[0].highlighted = true
|
|
||||||
gridModeButtons[1].highlighted = false
|
|
||||||
itemPage = 0
|
|
||||||
rebuild(currentFilter)
|
rebuild(currentFilter)
|
||||||
}
|
}
|
||||||
gridModeButtons[1].touchDownListener = { _, _, _, _ ->
|
navRemoCon.gridButtonListener = { _, _ ->
|
||||||
isCompactMode = true
|
isCompactMode = true
|
||||||
gridModeButtons[0].highlighted = false
|
|
||||||
gridModeButtons[1].highlighted = true
|
|
||||||
itemPage = 0
|
|
||||||
rebuild(currentFilter)
|
rebuild(currentFilter)
|
||||||
}
|
}
|
||||||
|
navRemoCon.scrollUpListener = { _, it ->
|
||||||
scrollUpButton.clickOnceListener = { _, _, _ ->
|
it.highlighted = false
|
||||||
scrollUpButton.highlighted = false
|
|
||||||
scrollItemPage(-1)
|
scrollItemPage(-1)
|
||||||
}
|
}
|
||||||
scrollDownButton.clickOnceListener = { _, _, _ ->
|
navRemoCon.scrollDownListener = { _, it ->
|
||||||
scrollDownButton.highlighted = false
|
it.highlighted = false
|
||||||
scrollItemPage(1)
|
scrollItemPage(1)
|
||||||
}
|
}
|
||||||
|
// draw wallet text
|
||||||
// if (is.mouseUp) handled by this.touchDown()
|
navRemoCon.extraDrawOpOnBottom = { ui, batch ->
|
||||||
|
if (drawWallet) {
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
walletText.forEachIndexed { index, it ->
|
||||||
|
batch.draw(
|
||||||
|
walletFont.get(0, it - '0'),
|
||||||
|
ui.gridModeButtons[0].posX - 1f, // scroll button size: 20px, font width: 20 px
|
||||||
|
ui.gridModeButtons[0].posY + height - index * walletFont.tileH - 18f
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private val upDownButtonGapToDots = 7 // apparent gap may vary depend on the texture itself
|
// private val upDownButtonGapToDots = 7 // apparent gap may vary depend on the texture itself
|
||||||
|
|
||||||
private fun getIconPosY(index: Int) =
|
// private fun getIconPosY(index: Int) =
|
||||||
posY + 8 + 26 * index
|
// posY + 8 + 26 * index
|
||||||
|
|
||||||
override fun render(batch: SpriteBatch, camera: Camera) {
|
override fun render(batch: SpriteBatch, camera: Camera) {
|
||||||
val posXDelta = posX - oldPosX
|
val posXDelta = posX - oldPosX
|
||||||
itemGrid.forEach { it.posX += posXDelta }
|
itemGrid.forEach { it.posX += posXDelta }
|
||||||
itemList.forEach { it.posX += posXDelta }
|
itemList.forEach { it.posX += posXDelta }
|
||||||
if (!hideSidebar) {
|
|
||||||
gridModeButtons.forEach { it.posX += posXDelta }
|
|
||||||
scrollUpButton.posX += posXDelta
|
|
||||||
scrollDownButton.posX += posXDelta
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun getScrollDotYHeight(i: Int) = scrollUpButton.posY + 14 + upDownButtonGapToDots + 10 * i
|
|
||||||
|
|
||||||
|
|
||||||
scrollDownButton.posY = getScrollDotYHeight(itemPageCount) + upDownButtonGapToDots
|
|
||||||
|
|
||||||
|
|
||||||
// define each button's highlighted status from the list of forceHighlighted, then render the button
|
// define each button's highlighted status from the list of forceHighlighted, then render the button
|
||||||
items.forEach {
|
items.forEach {
|
||||||
if (useHighlightingManager) it.forceHighlighted = forceHighlightList.contains(it.item?.dynamicID)
|
if (useHighlightingManager) it.forceHighlighted = forceHighlightList.contains(it.item?.dynamicID)
|
||||||
@@ -346,41 +302,7 @@ open class UIItemInventoryItemGrid(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!hideSidebar) {
|
if (!hideSidebar) {
|
||||||
// draw the tray
|
navRemoCon.render(batch, camera)
|
||||||
batch.color = Toolkit.Theme.COL_CELL_FILL
|
|
||||||
Toolkit.fillArea(batch, iconPosX - 4, getIconPosY(0) - 8, 28, height)
|
|
||||||
// cell border
|
|
||||||
batch.color = colourTheme.cellHighlightNormalCol
|
|
||||||
Toolkit.drawBoxBorder(batch, iconPosX - 4, getIconPosY(0) - 8, 28, height)
|
|
||||||
|
|
||||||
gridModeButtons.forEach { it.render(batch, camera) }
|
|
||||||
scrollUpButton.render(batch, camera)
|
|
||||||
scrollDownButton.render(batch, camera)
|
|
||||||
|
|
||||||
// draw scroll dots
|
|
||||||
for (i in 0 until itemPageCount) {
|
|
||||||
val colour = if (i == itemPage) Color.WHITE else Color(0xffffff7f.toInt())
|
|
||||||
|
|
||||||
batch.color = colour
|
|
||||||
batch.draw(
|
|
||||||
catBar.catIcons.get(if (i == itemPage) 20 else 21, 0),
|
|
||||||
iconPosX.toFloat(),
|
|
||||||
getScrollDotYHeight(i).toFloat()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// draw wallet text
|
|
||||||
if (drawWallet) {
|
|
||||||
batch.color = Color.WHITE
|
|
||||||
walletText.forEachIndexed { index, it ->
|
|
||||||
batch.draw(
|
|
||||||
walletFont.get(0, it - '0'),
|
|
||||||
gridModeButtons[0].posX - 1f, // scroll button size: 20px, font width: 20 px
|
|
||||||
gridModeButtons[0].posY + height - index * walletFont.tileH - 18f
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
super.render(batch, camera)
|
super.render(batch, camera)
|
||||||
@@ -424,9 +346,7 @@ open class UIItemInventoryItemGrid(
|
|||||||
|
|
||||||
|
|
||||||
if (!hideSidebar) {
|
if (!hideSidebar) {
|
||||||
gridModeButtons.forEach { it.update(delta) }
|
navRemoCon.update(delta)
|
||||||
scrollUpButton.update(delta)
|
|
||||||
scrollDownButton.update(delta)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -549,9 +469,7 @@ open class UIItemInventoryItemGrid(
|
|||||||
|
|
||||||
items.forEach { if (it.mouseUp) it.touchDown(screenX, screenY, pointer, button) }
|
items.forEach { if (it.mouseUp) it.touchDown(screenX, screenY, pointer, button) }
|
||||||
if (!hideSidebar) {
|
if (!hideSidebar) {
|
||||||
gridModeButtons.forEach { if (it.mouseUp) it.touchDown(screenX, screenY, pointer, button) }
|
navRemoCon.touchDown(screenX, screenY, pointer, button)
|
||||||
if (scrollUpButton.mouseUp) scrollUpButton.touchDown(screenX, screenY, pointer, button)
|
|
||||||
if (scrollDownButton.mouseUp) scrollDownButton.touchDown(screenX, screenY, pointer, button)
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,178 @@
|
|||||||
|
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.BlendMode
|
||||||
|
import net.torvald.terrarum.CommonResourcePool
|
||||||
|
import net.torvald.terrarum.toInt
|
||||||
|
import net.torvald.terrarum.ui.Toolkit
|
||||||
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
|
import net.torvald.terrarum.ui.UIItem
|
||||||
|
import net.torvald.terrarum.ui.UIItemImageButton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2023-06-17.
|
||||||
|
*/
|
||||||
|
class UIItemListNavBarVertical(
|
||||||
|
parentUI: UICanvas, initialX: Int, initialY: Int,
|
||||||
|
override val height: Int,
|
||||||
|
val hasGridModeButtons: Boolean, initialModeSelection: Int = 0,
|
||||||
|
private val colourTheme: InventoryCellColourTheme = UIItemInventoryCellCommonRes.defaultInventoryCellTheme,
|
||||||
|
var extraDrawOpOnBottom: (UIItemListNavBarVertical, SpriteBatch) -> Unit = { _,_ -> }
|
||||||
|
) : UIItem(parentUI, initialX, initialY) {
|
||||||
|
|
||||||
|
override val width = UIItemListNavBarVertical.WIDTH
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val WIDTH = 28
|
||||||
|
const val LIST_TO_CONTROL_GAP = 12
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getIconPosY(index: Int) =
|
||||||
|
posY + 26 * index
|
||||||
|
private val catIcons = CommonResourcePool.getAsTextureRegionPack("inventory_category")
|
||||||
|
private val iconPosX = posX + LIST_TO_CONTROL_GAP
|
||||||
|
|
||||||
|
val gridModeButtons = Array<UIItemImageButton>(2) { index ->
|
||||||
|
UIItemImageButton(
|
||||||
|
parentUI,
|
||||||
|
catIcons.get(index + 14, 0),
|
||||||
|
backgroundCol = Color(0),
|
||||||
|
activeBackCol = Color(0),
|
||||||
|
highlightBackCol = Color(0),
|
||||||
|
activeBackBlendMode = BlendMode.NORMAL,
|
||||||
|
activeCol = Toolkit.Theme.COL_MOUSE_UP,
|
||||||
|
initialX = iconPosX,
|
||||||
|
initialY = getIconPosY(index),
|
||||||
|
highlightable = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val scrollUpButton = UIItemImageButton(
|
||||||
|
parentUI,
|
||||||
|
catIcons.get(18, 0),
|
||||||
|
backgroundCol = Color(0),
|
||||||
|
activeBackCol = Color(0),
|
||||||
|
activeBackBlendMode = BlendMode.NORMAL,
|
||||||
|
activeCol = Toolkit.Theme.COL_MOUSE_UP,
|
||||||
|
initialX = iconPosX,
|
||||||
|
initialY = getIconPosY(2 - (!hasGridModeButtons).toInt(1)),
|
||||||
|
highlightable = false
|
||||||
|
)
|
||||||
|
|
||||||
|
val scrollDownButton = UIItemImageButton(
|
||||||
|
parentUI,
|
||||||
|
catIcons.get(19, 0),
|
||||||
|
backgroundCol = Color(0),
|
||||||
|
activeBackCol = Color(0),
|
||||||
|
activeBackBlendMode = BlendMode.NORMAL,
|
||||||
|
activeCol = Toolkit.Theme.COL_MOUSE_UP,
|
||||||
|
initialX = iconPosX,
|
||||||
|
initialY = getIconPosY(3 - (!hasGridModeButtons).toInt(1)),
|
||||||
|
highlightable = false
|
||||||
|
)
|
||||||
|
|
||||||
|
private val upDownButtonGapToDots = 7 // apparent gap may vary depend on the texture itself
|
||||||
|
|
||||||
|
init {
|
||||||
|
gridModeButtons[initialModeSelection].highlighted = true
|
||||||
|
|
||||||
|
gridModeButtons[0].touchDownListener = { _, _, _, _ ->
|
||||||
|
gridModeButtons[0].highlighted = true
|
||||||
|
gridModeButtons[1].highlighted = false
|
||||||
|
itemPage = 0
|
||||||
|
listButtonListener(this, gridModeButtons[0])
|
||||||
|
}
|
||||||
|
gridModeButtons[1].touchDownListener = { _, _, _, _ ->
|
||||||
|
gridModeButtons[0].highlighted = false
|
||||||
|
gridModeButtons[1].highlighted = true
|
||||||
|
itemPage = 0
|
||||||
|
gridButtonListener(this, gridModeButtons[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollUpButton.clickOnceListener = { _, _ ->
|
||||||
|
scrollUpButton.highlighted = false
|
||||||
|
scrollUpListener(this, scrollUpButton)
|
||||||
|
}
|
||||||
|
scrollDownButton.clickOnceListener = { _, _ ->
|
||||||
|
scrollDownButton.highlighted = false
|
||||||
|
scrollDownListener(this, scrollDownButton)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var listButtonListener: (UIItemListNavBarVertical, UIItemImageButton) -> Unit = { _,_ -> }
|
||||||
|
var gridButtonListener: (UIItemListNavBarVertical, UIItemImageButton) -> Unit = { _,_ -> }
|
||||||
|
var scrollUpListener: (UIItemListNavBarVertical, UIItemImageButton) -> Unit = { _,_ -> }
|
||||||
|
var scrollDownListener: (UIItemListNavBarVertical, UIItemImageButton) -> Unit = { _,_ -> }
|
||||||
|
var itemPageCount = 0
|
||||||
|
var itemPage = 0
|
||||||
|
|
||||||
|
|
||||||
|
override fun render(batch: SpriteBatch, camera: Camera) {
|
||||||
|
val posXDelta = posX - oldPosX
|
||||||
|
|
||||||
|
gridModeButtons.forEach { it.posX += posXDelta }
|
||||||
|
scrollUpButton.posX += posXDelta
|
||||||
|
scrollDownButton.posX += posXDelta
|
||||||
|
|
||||||
|
fun getScrollDotYHeight(i: Int) = scrollUpButton.posY + 14 + upDownButtonGapToDots + 10 * i
|
||||||
|
|
||||||
|
scrollDownButton.posY = getScrollDotYHeight(itemPageCount) + upDownButtonGapToDots
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// draw the tray
|
||||||
|
batch.color = Toolkit.Theme.COL_CELL_FILL
|
||||||
|
Toolkit.fillArea(batch, iconPosX - 4, getIconPosY(0) - 8, width, height)
|
||||||
|
// cell border
|
||||||
|
batch.color = colourTheme.cellHighlightNormalCol
|
||||||
|
Toolkit.drawBoxBorder(batch, iconPosX - 4, getIconPosY(0) - 8, width, height)
|
||||||
|
|
||||||
|
if (hasGridModeButtons) gridModeButtons.forEach { it.render(batch, camera) }
|
||||||
|
scrollUpButton.render(batch, camera)
|
||||||
|
scrollDownButton.render(batch, camera)
|
||||||
|
|
||||||
|
// draw scroll dots
|
||||||
|
for (i in 0 until itemPageCount) {
|
||||||
|
val colour = if (i == itemPage) Color.WHITE else Color(0xffffff7f.toInt())
|
||||||
|
|
||||||
|
batch.color = colour
|
||||||
|
batch.draw(
|
||||||
|
catIcons.get(if (i == itemPage) 20 else 21, 0),
|
||||||
|
iconPosX.toFloat(),
|
||||||
|
getScrollDotYHeight(i) - 2f
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extraDrawOpOnBottom(this, batch)
|
||||||
|
|
||||||
|
super.render(batch, camera)
|
||||||
|
|
||||||
|
oldPosX = posX
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(delta: Float) {
|
||||||
|
|
||||||
|
if (hasGridModeButtons) gridModeButtons.forEach { it.update(delta) }
|
||||||
|
scrollUpButton.update(delta)
|
||||||
|
scrollDownButton.update(delta)
|
||||||
|
|
||||||
|
super.update(delta)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||||
|
if (hasGridModeButtons) gridModeButtons.forEach { if (it.mouseUp) it.touchDown(screenX, screenY, pointer, button) }
|
||||||
|
if (scrollUpButton.mouseUp) scrollUpButton.touchDown(screenX, screenY, pointer, button)
|
||||||
|
if (scrollDownButton.mouseUp) scrollDownButton.touchDown(screenX, screenY, pointer, button)
|
||||||
|
return super.touchDown(screenX, screenY, pointer, button)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import net.torvald.terrarum.App
|
|||||||
import net.torvald.terrarum.CommonResourcePool
|
import net.torvald.terrarum.CommonResourcePool
|
||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
import net.torvald.terrarum.modulebasegame.serialise.WriteSavegame
|
import net.torvald.terrarum.modulebasegame.serialise.WriteSavegame
|
||||||
|
import net.torvald.terrarum.ui.Toolkit
|
||||||
import net.torvald.terrarum.ui.UICanvas
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
import net.torvald.terrarum.ui.UIItem
|
import net.torvald.terrarum.ui.UIItem
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
@@ -30,9 +31,10 @@ class UIItemSaving(parentUI: UICanvas, initialX: Int, initialY: Int) : UIItem(pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun render(batch: SpriteBatch, camera: Camera) {
|
override fun render(batch: SpriteBatch, camera: Camera) {
|
||||||
|
// these things will not scroll along with the parent GUI!
|
||||||
val t = Lang["MENU_IO_SAVING"]
|
val t = Lang["MENU_IO_SAVING"]
|
||||||
val tlen = App.fontGame.getWidth(t)
|
val tlen = App.fontGame.getWidth(t)
|
||||||
App.fontGame.draw(batch, t, (posX + (width - tlen) / 2).toFloat(), posY - 32f)
|
App.fontGame.draw(batch, t, (posX + (width - tlen) / 2).toFloat(), ((App.scr.height - circleSheet.tileH) / 2) - 40f)
|
||||||
|
|
||||||
// -1..63
|
// -1..63
|
||||||
val index = ((WriteSavegame.saveProgress / WriteSavegame.saveProgressMax) * circles).roundToInt() - 1
|
val index = ((WriteSavegame.saveProgress / WriteSavegame.saveProgressMax) * circles).roundToInt() - 1
|
||||||
@@ -41,7 +43,11 @@ class UIItemSaving(parentUI: UICanvas, initialX: Int, initialY: Int) : UIItem(pa
|
|||||||
val sy = index / circleSheet.horizontalCount
|
val sy = index / circleSheet.horizontalCount
|
||||||
// q&d fix for ArrayIndexOutOfBoundsException caused when saving huge world... wut?
|
// q&d fix for ArrayIndexOutOfBoundsException caused when saving huge world... wut?
|
||||||
if (sx in 0 until circleSheet.horizontalCount && sy in 0 until circleSheet.horizontalCount) {
|
if (sx in 0 until circleSheet.horizontalCount && sy in 0 until circleSheet.horizontalCount) {
|
||||||
batch.draw(circleSheet.get(sx, sy), (posX + (width - circleSheet.tileW) / 2).toFloat(), posY.toFloat())
|
batch.draw(
|
||||||
|
circleSheet.get(sx, sy),
|
||||||
|
((Toolkit.drawWidth - circleSheet.tileW) / 2).toFloat(),
|
||||||
|
((App.scr.height - circleSheet.tileH) / 2).toFloat()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ class UIKeyboardControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
|||||||
keycaps.values.forEach { addUIitem(it) }
|
keycaps.values.forEach { addUIitem(it) }
|
||||||
updateKeycaps()
|
updateKeycaps()
|
||||||
|
|
||||||
buttonReset.clickOnceListener = { x, y, button ->
|
buttonReset.clickOnceListener = { x, y ->
|
||||||
resetKeyConfig()
|
resetKeyConfig()
|
||||||
updateKeycaps()
|
updateKeycaps()
|
||||||
}
|
}
|
||||||
@@ -201,7 +201,9 @@ class UIKeyboardControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
|||||||
// todo show "Keyboard"/"Gamepad" accordingly
|
// todo show "Keyboard"/"Gamepad" accordingly
|
||||||
batch.color = Color.WHITE
|
batch.color = Color.WHITE
|
||||||
val title = Lang["MENU_CONTROLS_KEYBOARD"]
|
val title = Lang["MENU_CONTROLS_KEYBOARD"]
|
||||||
App.fontGame.draw(batch, title, drawX.toFloat() + (width - App.fontGame.getWidth(title)) / 2, drawY.toFloat())
|
App.fontUITitle.draw(batch, title, drawX.toFloat() + (width - App.fontUITitle.getWidth(title)) / 2, drawY.toFloat())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val desc = Lang["MENU_LABEL_KEYCONFIG_HELP1"]
|
val desc = Lang["MENU_LABEL_KEYCONFIG_HELP1"]
|
||||||
App.fontGame.draw(batch, desc, drawX.toFloat() + (width - App.fontGame.getWidth(desc)) / 2, drawY + 360f)
|
App.fontGame.draw(batch, desc, drawX.toFloat() + (width - App.fontGame.getWidth(desc)) / 2, drawY + 360f)
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ import net.torvald.terrarum.ui.Movement
|
|||||||
import net.torvald.terrarum.ui.Toolkit
|
import net.torvald.terrarum.ui.Toolkit
|
||||||
import net.torvald.terrarum.ui.UICanvas
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
import net.torvald.terrarum.ui.UIItem
|
import net.torvald.terrarum.ui.UIItem
|
||||||
|
import net.torvald.terrarum.utils.JsonFetcher
|
||||||
|
import net.torvald.terrarum.utils.forEachSiblings
|
||||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
@@ -55,6 +57,11 @@ val SAVE_CELL_HEIGHT = 120
|
|||||||
* WARNING: the values are not guaranteed to reset when the selector UI is closed!
|
* WARNING: the values are not guaranteed to reset when the selector UI is closed!
|
||||||
*/
|
*/
|
||||||
object UILoadGovernor {
|
object UILoadGovernor {
|
||||||
|
// used by the default save loader
|
||||||
|
var playerUUID: UUID? = null
|
||||||
|
var worldUUID: UUID? = null
|
||||||
|
var previousSaveWasLoaded = false
|
||||||
|
// used by the debug save loader
|
||||||
var playerDisk: DiskSkimmer? = null
|
var playerDisk: DiskSkimmer? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
printdbg(this, "Player selected: ${value?.diskFile?.name}")
|
printdbg(this, "Player selected: ${value?.diskFile?.name}")
|
||||||
@@ -71,15 +78,23 @@ object UILoadGovernor {
|
|||||||
printdbg(this, "Resetting player and world selection")
|
printdbg(this, "Resetting player and world selection")
|
||||||
playerDisk = null
|
playerDisk = null
|
||||||
worldDisk = null
|
worldDisk = null
|
||||||
|
|
||||||
|
playerUUID = null
|
||||||
|
worldUUID = null
|
||||||
|
previousSaveWasLoaded = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class Advanceable : UICanvas() {
|
||||||
|
abstract fun advanceMode(button: UIItem)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only works if current screen set by the App is [TitleScreen]
|
* Only works if current screen set by the App is [TitleScreen]
|
||||||
*
|
*
|
||||||
* Created by minjaesong on 2021-09-09.
|
* Created by minjaesong on 2021-09-09.
|
||||||
*/
|
*/
|
||||||
class UILoadDemoSavefiles(val remoCon: UIRemoCon) : UICanvas() {
|
class UILoadDemoSavefiles(val remoCon: UIRemoCon) : Advanceable() {
|
||||||
|
|
||||||
// private val hash = RandomWordsName(3)
|
// private val hash = RandomWordsName(3)
|
||||||
|
|
||||||
@@ -155,7 +170,7 @@ class UILoadDemoSavefiles(val remoCon: UIRemoCon) : UICanvas() {
|
|||||||
this.mode = mode
|
this.mode = mode
|
||||||
}
|
}
|
||||||
|
|
||||||
fun advanceMode() {
|
override fun advanceMode(button: UIItem) {
|
||||||
mode += 1
|
mode += 1
|
||||||
uiScroll = 0f
|
uiScroll = 0f
|
||||||
scrollFrom = 0
|
scrollFrom = 0
|
||||||
@@ -175,7 +190,7 @@ class UILoadDemoSavefiles(val remoCon: UIRemoCon) : UICanvas() {
|
|||||||
// read savegames
|
// read savegames
|
||||||
var savegamesCount = 0
|
var savegamesCount = 0
|
||||||
App.sortedSavegameWorlds.forEach { uuid ->
|
App.sortedSavegameWorlds.forEach { uuid ->
|
||||||
val skimmer = App.savegameWorlds[uuid]!!
|
val skimmer = App.savegameWorlds[uuid]!!.loadable()
|
||||||
val x = uiX
|
val x = uiX
|
||||||
val y = titleTopGradEnd + cellInterval * savegamesCount
|
val y = titleTopGradEnd + cellInterval * savegamesCount
|
||||||
try {
|
try {
|
||||||
@@ -190,7 +205,7 @@ class UILoadDemoSavefiles(val remoCon: UIRemoCon) : UICanvas() {
|
|||||||
|
|
||||||
savegamesCount = 0
|
savegamesCount = 0
|
||||||
App.sortedPlayers.forEach { uuid ->
|
App.sortedPlayers.forEach { uuid ->
|
||||||
val skimmer = App.savegamePlayers[uuid]!!
|
val skimmer = App.savegamePlayers[uuid]!!.loadable()
|
||||||
val x = uiX
|
val x = uiX
|
||||||
val y = titleTopGradEnd + cellInterval * savegamesCount
|
val y = titleTopGradEnd + cellInterval * savegamesCount
|
||||||
try {
|
try {
|
||||||
@@ -374,7 +389,7 @@ class UILoadDemoSavefiles(val remoCon: UIRemoCon) : UICanvas() {
|
|||||||
// draw texts
|
// draw texts
|
||||||
val loadGameTitleStr = Lang[titles[mode]]// + "$EMDASH$hash"
|
val loadGameTitleStr = Lang[titles[mode]]// + "$EMDASH$hash"
|
||||||
// "Game Load"
|
// "Game Load"
|
||||||
App.fontUITitle.draw(batch, loadGameTitleStr, (width - App.fontGame.getWidth(loadGameTitleStr)).div(2).toFloat(), titleTextPosY.toFloat())
|
App.fontUITitle.draw(batch, loadGameTitleStr, (width - App.fontUITitle.getWidth(loadGameTitleStr)).div(2).toFloat(), titleTextPosY.toFloat())
|
||||||
// Control help
|
// Control help
|
||||||
App.fontGame.draw(batch, controlHelp, uiX.toFloat(), controlHelperY.toFloat())
|
App.fontGame.draw(batch, controlHelp, uiX.toFloat(), controlHelperY.toFloat())
|
||||||
}
|
}
|
||||||
@@ -470,7 +485,7 @@ class UILoadDemoSavefiles(val remoCon: UIRemoCon) : UICanvas() {
|
|||||||
|
|
||||||
|
|
||||||
class UIItemPlayerCells(
|
class UIItemPlayerCells(
|
||||||
parent: UILoadDemoSavefiles,
|
parent: Advanceable,
|
||||||
initialX: Int,
|
initialX: Int,
|
||||||
initialY: Int,
|
initialY: Int,
|
||||||
val skimmer: DiskSkimmer) : UIItem(parent, initialX, initialY) {
|
val skimmer: DiskSkimmer) : UIItem(parent, initialX, initialY) {
|
||||||
@@ -478,9 +493,11 @@ class UIItemPlayerCells(
|
|||||||
override val width = SAVE_CELL_WIDTH
|
override val width = SAVE_CELL_WIDTH
|
||||||
override val height = SAVE_CELL_HEIGHT
|
override val height = SAVE_CELL_HEIGHT
|
||||||
|
|
||||||
override var clickOnceListener: ((Int, Int, Int) -> Unit)? = { _: Int, _: Int, _: Int ->
|
override var clickOnceListener: ((Int, Int) -> Unit) = { _: Int, _: Int ->
|
||||||
UILoadGovernor.playerDisk = skimmer
|
UILoadGovernor.playerDisk = skimmer
|
||||||
parent.advanceMode()
|
UILoadGovernor.playerUUID = playerUUID
|
||||||
|
UILoadGovernor.worldUUID = worldUUID
|
||||||
|
parent.advanceMode(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var playerName: String = "$EMDASH"
|
private var playerName: String = "$EMDASH"
|
||||||
@@ -488,28 +505,25 @@ class UIItemPlayerCells(
|
|||||||
private var lastPlayTime: String = "????-??-?? --:--:--"
|
private var lastPlayTime: String = "????-??-?? --:--:--"
|
||||||
private var totalPlayTime: String = "--h--m--s"
|
private var totalPlayTime: String = "--h--m--s"
|
||||||
|
|
||||||
private var playerUUID: UUID? = null
|
lateinit var playerUUID: UUID; private set
|
||||||
|
lateinit var worldUUID: UUID; private set
|
||||||
|
|
||||||
init {
|
init {
|
||||||
skimmer.getFile(SAVEGAMEINFO)?.bytes?.let {
|
skimmer.getFile(SAVEGAMEINFO)?.bytes?.let {
|
||||||
val json = JsonReader().parse(ByteArray64Reader(it, Common.CHARSET))
|
var lastPlayTime0 = 0L
|
||||||
|
|
||||||
playerUUID = UUID.fromString(json["uuid"]?.asString())
|
JsonFetcher.readFromJsonString(ByteArray64Reader(it, Common.CHARSET)).forEachSiblings { name, value ->
|
||||||
val worldUUID = UUID.fromString(json["worldCurrentlyPlaying"]?.asString())
|
if (name == "uuid") playerUUID = UUID.fromString(value.asString())
|
||||||
|
if (name == "worldCurrentlyPlaying") worldUUID = UUID.fromString(value.asString())
|
||||||
|
if (name == "totalPlayTime") totalPlayTime = parseDuration(value.asLong())
|
||||||
|
if (name == "lastPlayTime") lastPlayTime0 = value.asLong()
|
||||||
|
}
|
||||||
|
|
||||||
App.savegamePlayersName[playerUUID]?.let { if (it.isNotBlank()) playerName = it else "(name)" }
|
App.savegamePlayersName[playerUUID]?.let { if (it.isNotBlank()) playerName = it else "(name)" }
|
||||||
App.savegameWorldsName[worldUUID]?.let { if (it.isNotBlank()) worldName = it }
|
App.savegameWorldsName[worldUUID]?.let { if (it.isNotBlank()) worldName = it }
|
||||||
/*json["lastPlayTime"]?.asString()?.let {
|
lastPlayTime = Instant.ofEpochSecond(lastPlayTime0)
|
||||||
lastPlayTime = Instant.ofEpochSecond(it.toLong())
|
|
||||||
.atZone(TimeZone.getDefault().toZoneId())
|
|
||||||
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
|
|
||||||
}*/
|
|
||||||
lastPlayTime = Instant.ofEpochSecond(skimmer.getLastModifiedTime())
|
|
||||||
.atZone(TimeZone.getDefault().toZoneId())
|
.atZone(TimeZone.getDefault().toZoneId())
|
||||||
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
|
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
|
||||||
json["totalPlayTime"]?.asString()?.let {
|
|
||||||
totalPlayTime = parseDuration(it.toLong())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -541,10 +555,12 @@ class UIItemPlayerCells(
|
|||||||
private var highlightCol: Color = defaultCol
|
private var highlightCol: Color = defaultCol
|
||||||
private var highlightTextCol: Color = defaultCol
|
private var highlightTextCol: Color = defaultCol
|
||||||
|
|
||||||
|
var forceMouseDown = false
|
||||||
|
|
||||||
override fun update(delta: Float) {
|
override fun update(delta: Float) {
|
||||||
super.update(delta)
|
super.update(delta)
|
||||||
highlightCol = if (mouseUp) litCol else defaultCol
|
highlightCol = if (mouseUp && !forceMouseDown) litCol else defaultCol
|
||||||
highlightTextCol = if (mouseUp) litCol else Toolkit.Theme.COL_LIST_DEFAULT
|
highlightTextCol = if (mouseUp && !forceMouseDown) litCol else Toolkit.Theme.COL_LIST_DEFAULT
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(batch: SpriteBatch, camera: Camera) {
|
override fun render(batch: SpriteBatch, camera: Camera) {
|
||||||
@@ -670,7 +686,7 @@ class UIItemPlayerCells(
|
|||||||
|
|
||||||
|
|
||||||
class UIItemWorldCells(
|
class UIItemWorldCells(
|
||||||
parent: UILoadDemoSavefiles,
|
parent: Advanceable,
|
||||||
initialX: Int,
|
initialX: Int,
|
||||||
initialY: Int,
|
initialY: Int,
|
||||||
val skimmer: DiskSkimmer) : UIItem(parent, initialX, initialY) {
|
val skimmer: DiskSkimmer) : UIItem(parent, initialX, initialY) {
|
||||||
@@ -685,9 +701,6 @@ class UIItemWorldCells(
|
|||||||
private val lastPlayedTimestamp: String
|
private val lastPlayedTimestamp: String
|
||||||
|
|
||||||
init {
|
init {
|
||||||
printdbg(this, "Rebuilding skimmer for savefile ${skimmer.diskFile.absolutePath}")
|
|
||||||
skimmer.rebuild()
|
|
||||||
|
|
||||||
metaFile = skimmer.getFile(-1)
|
metaFile = skimmer.getFile(-1)
|
||||||
if (metaFile == null) saveDamaged = true
|
if (metaFile == null) saveDamaged = true
|
||||||
|
|
||||||
@@ -699,14 +712,18 @@ class UIItemWorldCells(
|
|||||||
saveDamaged = saveDamaged or checkForSavegameDamage(skimmer)
|
saveDamaged = saveDamaged or checkForSavegameDamage(skimmer)
|
||||||
|
|
||||||
if (metaFile != null) {
|
if (metaFile != null) {
|
||||||
val worldJson = JsonReader().parse(ByteArray64Reader(metaFile.bytes, Common.CHARSET))
|
// val lastplay_t = skimmer.getLastModifiedTime()//worldJson["lastPlayTime"].asLong()
|
||||||
val lastplay_t = skimmer.getLastModifiedTime()//worldJson["lastPlayTime"].asLong()
|
var playtime_t = ""
|
||||||
val playtime_t = worldJson["totalPlayTime"].asLong()
|
var lastplay_t = 0L
|
||||||
|
JsonFetcher.readFromJsonString(ByteArray64Reader(metaFile.bytes, Common.CHARSET)).forEachSiblings { name, value ->
|
||||||
|
if (name == "lastPlayTime") lastplay_t = value.asLong()
|
||||||
|
if (name == "totalPlayTime") playtime_t = parseDuration(value.asLong())
|
||||||
|
}
|
||||||
lastPlayedTimestamp =
|
lastPlayedTimestamp =
|
||||||
Instant.ofEpochSecond(lastplay_t)
|
Instant.ofEpochSecond(lastplay_t)
|
||||||
.atZone(TimeZone.getDefault().toZoneId())
|
.atZone(TimeZone.getDefault().toZoneId())
|
||||||
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) +
|
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) +
|
||||||
"/${parseDuration(playtime_t)}"
|
"/$playtime_t"
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lastPlayedTimestamp = "--:--:--/--h--m--s"
|
lastPlayedTimestamp = "--:--:--/--h--m--s"
|
||||||
@@ -739,9 +756,9 @@ class UIItemWorldCells(
|
|||||||
|
|
||||||
private var highlightCol: Color = Toolkit.Theme.COL_LIST_DEFAULT
|
private var highlightCol: Color = Toolkit.Theme.COL_LIST_DEFAULT
|
||||||
|
|
||||||
override var clickOnceListener: ((Int, Int, Int) -> Unit)? = { _: Int, _: Int, _: Int ->
|
override var clickOnceListener: ((Int, Int) -> Unit) = { _: Int, _: Int ->
|
||||||
UILoadGovernor.worldDisk = skimmer
|
UILoadGovernor.worldDisk = skimmer
|
||||||
parent.advanceMode()
|
parent.advanceMode(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal var hasTexture = false
|
internal var hasTexture = false
|
||||||
|
|||||||
709
src/net/torvald/terrarum/modulebasegame/ui/UILoadSavegame.kt
Normal file
709
src/net/torvald/terrarum/modulebasegame/ui/UILoadSavegame.kt
Normal file
@@ -0,0 +1,709 @@
|
|||||||
|
package net.torvald.terrarum.modulebasegame.ui
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx
|
||||||
|
import com.badlogic.gdx.Input
|
||||||
|
import com.badlogic.gdx.graphics.*
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||||
|
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||||
|
import com.badlogic.gdx.utils.Disposable
|
||||||
|
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||||
|
import net.torvald.unicode.getKeycapConsole
|
||||||
|
import net.torvald.unicode.getKeycapPC
|
||||||
|
import net.torvald.terrarum.*
|
||||||
|
import net.torvald.terrarum.App.printdbg
|
||||||
|
import net.torvald.terrarum.langpack.Lang
|
||||||
|
import net.torvald.terrarum.savegame.ByteArray64InputStream
|
||||||
|
import net.torvald.terrarum.savegame.EntryFile
|
||||||
|
import net.torvald.terrarum.modulebasegame.serialise.LoadSavegame
|
||||||
|
import net.torvald.terrarum.savegame.VDFileID.PLAYER_SCREENSHOT
|
||||||
|
import net.torvald.terrarum.ui.*
|
||||||
|
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
import java.util.*
|
||||||
|
import java.util.zip.GZIPInputStream
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only works if current screen set by the App is [TitleScreen]
|
||||||
|
*
|
||||||
|
* Created by minjaesong on 2023-06-24.
|
||||||
|
*/
|
||||||
|
class UILoadSavegame(val remoCon: UIRemoCon) : Advanceable() {
|
||||||
|
|
||||||
|
// private val hash = RandomWordsName(3)
|
||||||
|
|
||||||
|
init {
|
||||||
|
CommonResourcePool.addToLoadingList("terrarum-defaultsavegamethumb") {
|
||||||
|
TextureRegion(Texture(Gdx.files.internal("assets/graphics/gui/savegame_thumb_placeholder.png")))
|
||||||
|
}
|
||||||
|
CommonResourcePool.addToLoadingList("savegame_status_icon") {
|
||||||
|
TextureRegionPack("assets/graphics/gui/savegame_status_icon.tga", 24, 24)
|
||||||
|
}
|
||||||
|
CommonResourcePool.loadAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
override var width: Int
|
||||||
|
get() = Toolkit.drawWidth
|
||||||
|
set(value) {}
|
||||||
|
override var height: Int
|
||||||
|
get() = App.scr.height
|
||||||
|
set(value) {}
|
||||||
|
override var openCloseTime: Second = OPENCLOSE_GENERIC
|
||||||
|
|
||||||
|
|
||||||
|
private val shapeRenderer = App.makeShapeRenderer()
|
||||||
|
|
||||||
|
|
||||||
|
internal val uiWidth = SAVE_CELL_WIDTH
|
||||||
|
internal val uiX: Int
|
||||||
|
get() = (Toolkit.drawWidth - uiWidth) / 2
|
||||||
|
internal val uiXdiffChatOverlay = App.scr.chatWidth / 2
|
||||||
|
|
||||||
|
internal val textH = App.fontGame.lineHeight.toInt()
|
||||||
|
|
||||||
|
internal val cellGap = 20
|
||||||
|
internal val cellInterval = cellGap + SAVE_CELL_HEIGHT
|
||||||
|
internal val gradAreaHeight = 32
|
||||||
|
|
||||||
|
// internal val titleTextPosY: Int = App.scr.tvSafeGraphicsHeight + 10
|
||||||
|
internal val titleTopGradStart: Int = App.scr.tvSafeGraphicsHeight
|
||||||
|
internal val titleTopGradEnd: Int = titleTopGradStart + gradAreaHeight
|
||||||
|
internal val titleBottomGradStart: Int = height - App.scr.tvSafeGraphicsHeight - gradAreaHeight
|
||||||
|
internal val titleBottomGradEnd: Int = titleBottomGradStart + gradAreaHeight
|
||||||
|
internal val controlHelperY: Int = titleBottomGradStart + gradAreaHeight - textH
|
||||||
|
|
||||||
|
|
||||||
|
private val controlHelp: String
|
||||||
|
get() = if (App.environment == RunningEnvironment.PC)
|
||||||
|
"${getKeycapPC(App.getConfigInt("control_key_up"))}${getKeycapPC(App.getConfigInt("control_key_down"))}" +
|
||||||
|
" ${Lang["MENU_CONTROLS_SCROLL"]}"
|
||||||
|
else
|
||||||
|
"${getKeycapConsole('R')} ${Lang["MENU_CONTROLS_SCROLL"]}"
|
||||||
|
|
||||||
|
|
||||||
|
private var scrollAreaHeight = height - 2 * App.scr.tvSafeGraphicsHeight - 64
|
||||||
|
private var listScroll = 0 // only update when animation is finished
|
||||||
|
private var savesVisible = (scrollAreaHeight + cellGap) / cellInterval
|
||||||
|
|
||||||
|
private var uiScroll = 0f
|
||||||
|
private var scrollFrom = 0
|
||||||
|
private var scrollTarget = 0
|
||||||
|
private var scrollAnimCounter = 0f
|
||||||
|
private val scrollAnimLen = 0.1f
|
||||||
|
|
||||||
|
private var sliderFBO = FrameBuffer(Pixmap.Format.RGBA8888, uiWidth + 10, height, false)
|
||||||
|
|
||||||
|
private var showSpinner = false
|
||||||
|
|
||||||
|
private val playerCells = ArrayList<UIItemPlayerCells>()
|
||||||
|
|
||||||
|
var mode = 0 // 0: show players, 1: show worlds
|
||||||
|
private set(value) {
|
||||||
|
touchLatched = true
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
|
||||||
|
private val MODE_SELECT = 0
|
||||||
|
private val MODE_SELECT_AFTER = 1
|
||||||
|
private val MODE_SAVE_MULTIPLE_CHOICES = 2
|
||||||
|
private val MODE_LOAD_DA_SHIT_ALREADY = 255
|
||||||
|
private val MODE_SAVE_DAMAGED = 256
|
||||||
|
private val MODE_SAVE_DELETE = 512
|
||||||
|
private val MODE_SAVE_DELETE_CONFIRM = 513
|
||||||
|
|
||||||
|
private var buttonSelectedForDeletion: UIItemPlayerCells? = null
|
||||||
|
|
||||||
|
private val goButtonWidth = 180
|
||||||
|
private val drawX = (Toolkit.drawWidth - 480) / 2
|
||||||
|
private val drawY = (App.scr.height - 480) / 2
|
||||||
|
private val corruptedBackButton = UIItemTextButton(this, "MENU_LABEL_BACK", (Toolkit.drawWidth - goButtonWidth) / 2, drawY + 480 - 24, goButtonWidth, true, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
|
||||||
|
private val confirmCancelButton = UIItemTextButton(this, "MENU_LABEL_CANCEL", drawX + (240 - goButtonWidth) / 2, drawY + 480 - 24, goButtonWidth, true, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
|
||||||
|
private val confirmDeleteButton = UIItemTextButton(this, "MENU_LABEL_DELETE", drawX + 240 + (240 - goButtonWidth) / 2, drawY + 480- 24, goButtonWidth, true, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true, inactiveCol = Toolkit.Theme.COL_RED, activeCol = Toolkit.Theme.COL_REDD)
|
||||||
|
|
||||||
|
private lateinit var loadables: SavegameCollectionPair
|
||||||
|
|
||||||
|
private lateinit var loadManualThumbButton: UIItemImageButton
|
||||||
|
private lateinit var loadAutoThumbButton: UIItemImageButton
|
||||||
|
|
||||||
|
private val disposablePool = ArrayList<Disposable>()
|
||||||
|
|
||||||
|
private fun DiskPair.getThumbnail(): TextureRegion {
|
||||||
|
return this.player.requestFile(PLAYER_SCREENSHOT).let { file ->
|
||||||
|
CommonResourcePool.getAsTextureRegion("terrarum-defaultsavegamethumb")
|
||||||
|
|
||||||
|
if (file != null) {
|
||||||
|
val zippedTga = (file.contents as EntryFile).bytes
|
||||||
|
val gzin = GZIPInputStream(ByteArray64InputStream(zippedTga))
|
||||||
|
val tgaFileContents = gzin.readAllBytes(); gzin.close()
|
||||||
|
val pixmap = Pixmap(tgaFileContents, 0, tgaFileContents.size)
|
||||||
|
TextureRegion(Texture(pixmap)).also {
|
||||||
|
disposablePool.add(it.texture)
|
||||||
|
// do cropping and resizing
|
||||||
|
it.setRegion(
|
||||||
|
(pixmap.width - imageButtonW*2) / 2,
|
||||||
|
(pixmap.height - imageButtonH*2) / 2,
|
||||||
|
imageButtonW * 2,
|
||||||
|
imageButtonH * 2
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CommonResourcePool.getAsTextureRegion("terrarum-defaultsavegamethumb")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val altSelDrawW = 640
|
||||||
|
private val altSelHdrawW = altSelDrawW / 2
|
||||||
|
private val altSelDrawH = 480
|
||||||
|
private val imageButtonW = 300
|
||||||
|
private val imageButtonH = 240
|
||||||
|
private val altSelDrawY = ((App.scr.height - altSelDrawH)/2)
|
||||||
|
private val altSelQdrawW = altSelDrawW / 4
|
||||||
|
private val altSelQQQdrawW = altSelDrawW * 3 / 4
|
||||||
|
|
||||||
|
private fun getDrawTextualInfoFun(disks: DiskPair): (UIItem, SpriteBatch) -> Unit {
|
||||||
|
val lastPlayedStamp = Instant.ofEpochSecond(disks.player.getLastModifiedTime())
|
||||||
|
.atZone(TimeZone.getDefault().toZoneId())
|
||||||
|
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
|
||||||
|
return { item: UIItem, batch: SpriteBatch ->
|
||||||
|
App.fontSmallNumbers.draw(batch, lastPlayedStamp, item.posX + 5f, item.posY + 3f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
corruptedBackButton.clickOnceListener = { _,_ -> remoCon.openUI(UILoadSavegame(remoCon)) }
|
||||||
|
confirmCancelButton.clickOnceListener = { _, _ -> remoCon.openUI(UILoadSavegame(remoCon)) }
|
||||||
|
confirmDeleteButton.clickOnceListener = { _,_ ->
|
||||||
|
val pu = buttonSelectedForDeletion!!.playerUUID
|
||||||
|
val wu = buttonSelectedForDeletion!!.worldUUID
|
||||||
|
App.savegamePlayers[pu]?.moveToRecycle(App.recycledPlayersDir)?.let {
|
||||||
|
App.sortedPlayers.remove(pu)
|
||||||
|
App.savegamePlayers.remove(pu)
|
||||||
|
App.savegamePlayersName.remove(pu)
|
||||||
|
}
|
||||||
|
// don't delete the world please
|
||||||
|
remoCon.openUI(UILoadSavegame(remoCon))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun advanceMode(button: UIItem) {
|
||||||
|
printdbg(this, "advanceMode ${button.javaClass.canonicalName}")
|
||||||
|
|
||||||
|
mode += 1
|
||||||
|
uiScroll = 0f
|
||||||
|
scrollFrom = 0
|
||||||
|
scrollTarget = 0
|
||||||
|
scrollAnimCounter = 0f
|
||||||
|
loadFired = 0
|
||||||
|
|
||||||
|
printdbg(this, "savelist mode: $mode")
|
||||||
|
|
||||||
|
// look for recently played world
|
||||||
|
if (mode == MODE_SELECT_AFTER) {
|
||||||
|
|
||||||
|
// select the most recent loadable save by comparing manual and autosaves, NOT JUST going with loadable()
|
||||||
|
printdbg(this, "Load playerUUID: ${UILoadGovernor.playerUUID}, worldUUID: ${UILoadGovernor.worldUUID}")
|
||||||
|
loadables = SavegameCollectionPair(App.savegamePlayers[UILoadGovernor.playerUUID], App.savegameWorlds[UILoadGovernor.worldUUID])
|
||||||
|
|
||||||
|
mode = if (loadables.moreRecentAutosaveAvailable()) {
|
||||||
|
// make choice for load manual or auto, if available
|
||||||
|
|
||||||
|
val autoThumb = loadables.getAutoSave()!!.getThumbnail()
|
||||||
|
val manualThumb = loadables.getManualSave()!!.getThumbnail()
|
||||||
|
|
||||||
|
loadManualThumbButton = UIItemImageButton(this, manualThumb,
|
||||||
|
initialX = (Toolkit.drawWidth - altSelDrawW)/2 + altSelQdrawW - imageButtonW/2,
|
||||||
|
initialY = altSelDrawY + 120,
|
||||||
|
width = imageButtonW,
|
||||||
|
height = imageButtonH,
|
||||||
|
imageDrawWidth = imageButtonW,
|
||||||
|
imageDrawHeight = imageButtonH,
|
||||||
|
highlightable = false,
|
||||||
|
useBorder = true,
|
||||||
|
).also {
|
||||||
|
it.extraDrawOp = getDrawTextualInfoFun(loadables.getManualSave()!!)
|
||||||
|
it.clickOnceListener = { _,_ ->
|
||||||
|
loadables.getManualSave()!!.let {
|
||||||
|
UILoadGovernor.playerDisk = it.player
|
||||||
|
UILoadGovernor.worldDisk = it.world
|
||||||
|
}
|
||||||
|
mode = MODE_LOAD_DA_SHIT_ALREADY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadAutoThumbButton = UIItemImageButton(this, autoThumb,
|
||||||
|
initialX = (Toolkit.drawWidth - altSelDrawW)/2 + altSelQQQdrawW - imageButtonW/2,
|
||||||
|
initialY = altSelDrawY + 120,
|
||||||
|
width = imageButtonW,
|
||||||
|
height = imageButtonH,
|
||||||
|
imageDrawWidth = imageButtonW,
|
||||||
|
imageDrawHeight = imageButtonH,
|
||||||
|
highlightable = false,
|
||||||
|
useBorder = true,
|
||||||
|
).also {
|
||||||
|
it.extraDrawOp = getDrawTextualInfoFun(loadables.getAutoSave()!!)
|
||||||
|
it.clickOnceListener = { _,_ ->
|
||||||
|
loadables.getAutoSave()!!.let {
|
||||||
|
UILoadGovernor.playerDisk = it.player
|
||||||
|
UILoadGovernor.worldDisk = it.world
|
||||||
|
}
|
||||||
|
mode = MODE_LOAD_DA_SHIT_ALREADY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MODE_SAVE_MULTIPLE_CHOICES
|
||||||
|
}
|
||||||
|
else if (!loadables.saveAvaliable()) {
|
||||||
|
// show save is damaged and cannot be loaded
|
||||||
|
MODE_SAVE_DAMAGED
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val (p, w) = loadables.getLoadableSave()!!
|
||||||
|
UILoadGovernor.playerDisk = p; UILoadGovernor.worldDisk = w
|
||||||
|
|
||||||
|
if (loadables.newerSaveIsDamaged) {
|
||||||
|
UILoadGovernor.previousSaveWasLoaded = true
|
||||||
|
}
|
||||||
|
|
||||||
|
MODE_LOAD_DA_SHIT_ALREADY
|
||||||
|
|
||||||
|
|
||||||
|
// test codes //
|
||||||
|
|
||||||
|
/*val autoThumb = loadables.getManualSave()!!.getThumbnail()
|
||||||
|
val manualThumb = loadables.getManualSave()!!.getThumbnail()
|
||||||
|
|
||||||
|
loadManualThumbButton = UIItemImageButton(this, manualThumb,
|
||||||
|
initialX = (Toolkit.drawWidth - altSelDrawW)/2 + altSelQdrawW - imageButtonW/2,
|
||||||
|
initialY = altSelDrawY + 120,
|
||||||
|
width = imageButtonW,
|
||||||
|
height = imageButtonH,
|
||||||
|
imageDrawWidth = imageButtonW,
|
||||||
|
imageDrawHeight = imageButtonH,
|
||||||
|
highlightable = false,
|
||||||
|
useBorder = true,
|
||||||
|
).also {
|
||||||
|
it.extraDrawOp = getDrawTextualInfoFun(loadables.getManualSave()!!)
|
||||||
|
it.clickOnceListener = { _,_ ->
|
||||||
|
loadables.getManualSave()!!.let {
|
||||||
|
UILoadGovernor.playerDisk = it.player
|
||||||
|
UILoadGovernor.worldDisk = it.world
|
||||||
|
}
|
||||||
|
mode = MODE_LOAD_DA_SHIT_ALREADY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadAutoThumbButton = UIItemImageButton(this, autoThumb,
|
||||||
|
initialX = (Toolkit.drawWidth - altSelDrawW)/2 + altSelQQQdrawW - imageButtonW/2,
|
||||||
|
initialY = altSelDrawY + 120,
|
||||||
|
width = imageButtonW,
|
||||||
|
height = imageButtonH,
|
||||||
|
imageDrawWidth = imageButtonW,
|
||||||
|
imageDrawHeight = imageButtonH,
|
||||||
|
highlightable = false,
|
||||||
|
useBorder = true,
|
||||||
|
).also {
|
||||||
|
it.extraDrawOp = getDrawTextualInfoFun(loadables.getManualSave()!!)
|
||||||
|
it.clickOnceListener = { _,_ ->
|
||||||
|
loadables.getManualSave()!!.let {
|
||||||
|
UILoadGovernor.playerDisk = it.player
|
||||||
|
UILoadGovernor.worldDisk = it.world
|
||||||
|
}
|
||||||
|
mode = MODE_LOAD_DA_SHIT_ALREADY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MODE_SAVE_MULTIPLE_CHOICES*/
|
||||||
|
}
|
||||||
|
|
||||||
|
printdbg(this, "mode = $mode")
|
||||||
|
}
|
||||||
|
else if (mode == MODE_SAVE_DELETE_CONFIRM) {
|
||||||
|
// confirm deletion of selected player
|
||||||
|
buttonSelectedForDeletion = (button as UIItemPlayerCells).also {
|
||||||
|
deleteCellPosYstart = it.posY.toFloat()
|
||||||
|
it.forceMouseDown = true
|
||||||
|
it.update(0.01f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun show() {
|
||||||
|
try {
|
||||||
|
remoCon.handler.lockToggle()
|
||||||
|
showSpinner = true
|
||||||
|
|
||||||
|
Thread {
|
||||||
|
// read savegames
|
||||||
|
var savegamesCount = 0
|
||||||
|
App.sortedPlayers.forEach { uuid ->
|
||||||
|
val skimmer = App.savegamePlayers[uuid]!!.loadable()
|
||||||
|
val x = uiX
|
||||||
|
val y = titleTopGradEnd + cellInterval * savegamesCount
|
||||||
|
try {
|
||||||
|
playerCells.add(UIItemPlayerCells(this, x, y, skimmer))
|
||||||
|
savegamesCount += 1
|
||||||
|
}
|
||||||
|
catch (e: Throwable) {
|
||||||
|
System.err.println("[UILoadSavegame] Error while loading Player '${skimmer.diskFile.absolutePath}'")
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
remoCon.handler.unlockToggle()
|
||||||
|
showSpinner = false
|
||||||
|
}.start()
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (e: UninitializedPropertyAccessException) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hide() {
|
||||||
|
playerCells.forEach { it.dispose() }
|
||||||
|
playerCells.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
private var touchLatched = false
|
||||||
|
|
||||||
|
private fun getCells() = playerCells
|
||||||
|
private var loadFired = 0
|
||||||
|
private var oldMode = -1
|
||||||
|
|
||||||
|
private val mode1Node = Yaml(UITitleRemoConYaml.injectedMenuSingleCharSel).parse()
|
||||||
|
// private val mode2Node = Yaml(UITitleRemoConYaml.injectedMenuSingleWorldSel).parse()
|
||||||
|
|
||||||
|
// private val menus = listOf(mode1Node, mode2Node)
|
||||||
|
|
||||||
|
private val deleteCharacterButton = UIItemTextButton(
|
||||||
|
this, "CONTEXT_CHARACTER_DELETE",
|
||||||
|
UIRemoCon.menubarOffX - UIRemoCon.UIRemoConElement.paddingLeft + 72,
|
||||||
|
UIRemoCon.menubarOffY - UIRemoCon.UIRemoConElement.lineHeight * 3 + 16,
|
||||||
|
remoCon.width + UIRemoCon.UIRemoConElement.paddingLeft,
|
||||||
|
true,
|
||||||
|
inactiveCol = Toolkit.Theme.COL_RED,
|
||||||
|
activeCol = Toolkit.Theme.COL_REDD,
|
||||||
|
hitboxSize = UIRemoCon.UIRemoConElement.lineHeight - 2,
|
||||||
|
alignment = UIItemTextButton.Companion.Alignment.LEFT
|
||||||
|
).also {
|
||||||
|
it.clickOnceListener = { _,_ ->
|
||||||
|
mode = MODE_SAVE_DELETE
|
||||||
|
it.highlighted = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
// this UI will NOT persist; the parent of the mode1Node must be set using an absolute value (e.g. treeRoot, not remoCon.currentRemoConContents)
|
||||||
|
|
||||||
|
//printdbg(this, "UILoadSavegame called, from:")
|
||||||
|
//printStackTrace(this)
|
||||||
|
|
||||||
|
mode1Node.parent = remoCon.treeRoot
|
||||||
|
// mode2Node.parent = mode1Node
|
||||||
|
|
||||||
|
mode1Node.data = "MENU_MODE_SINGLEPLAYER : net.torvald.terrarum.modulebasegame.ui.UILoadSavegame"
|
||||||
|
// mode2Node.data = "MENU_MODE_SINGLEPLAYER : net.torvald.terrarum.modulebasegame.ui.UILoadSavegame"
|
||||||
|
|
||||||
|
// printdbg(this, "mode1Node parent: ${mode1Node.parent?.data}") // will be 'null' because the parent is the root node
|
||||||
|
// printdbg(this, "mode1Node data: ${mode1Node.data}")
|
||||||
|
// printdbg(this, "mode2Node data: ${mode2Node.data}")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun modeChangedHandler(mode: Int) {
|
||||||
|
printdbg(this, "Change mode: $oldMode -> $mode")
|
||||||
|
// remoCon.setNewRemoConContents(menus[mode])
|
||||||
|
remoCon.setNewRemoConContents(mode1Node)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateUI(delta: Float) {
|
||||||
|
if (mode == MODE_SELECT || mode == MODE_SAVE_DELETE) {
|
||||||
|
|
||||||
|
if (oldMode != mode) {
|
||||||
|
modeChangedHandler(mode)
|
||||||
|
oldMode = mode
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scrollTarget != listScroll) {
|
||||||
|
if (scrollAnimCounter < scrollAnimLen) {
|
||||||
|
scrollAnimCounter += delta
|
||||||
|
uiScroll = Movement.fastPullOut(
|
||||||
|
scrollAnimCounter / scrollAnimLen,
|
||||||
|
listScroll * cellInterval.toFloat(),
|
||||||
|
scrollTarget * cellInterval.toFloat()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scrollAnimCounter = 0f
|
||||||
|
listScroll = scrollTarget
|
||||||
|
uiScroll = cellInterval.toFloat() * scrollTarget
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val cells = getCells()
|
||||||
|
|
||||||
|
for (index in 0 until cells.size) {
|
||||||
|
|
||||||
|
|
||||||
|
val it = cells[index]
|
||||||
|
if (index in listScroll - 2 until listScroll + savesVisible + 2) {
|
||||||
|
// re-position
|
||||||
|
it.posY = (it.initialY - uiScroll).roundToInt()
|
||||||
|
it.update(delta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == MODE_SAVE_DELETE_CONFIRM && deleteCellAnimCounter <= scrollAnimLen) {
|
||||||
|
// do transitional moving stuff
|
||||||
|
buttonSelectedForDeletion?.posY = Movement.fastPullOut(deleteCellAnimCounter / scrollAnimLen, deleteCellPosYstart, (titleTopGradEnd + cellInterval).toFloat()).roundToInt()
|
||||||
|
|
||||||
|
deleteCellAnimCounter += delta
|
||||||
|
if (deleteCellAnimCounter > scrollAnimLen) deleteCellAnimCounter = scrollAnimLen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var deleteCellAnimCounter = 0f
|
||||||
|
private var deleteCellPosYstart = 0f
|
||||||
|
|
||||||
|
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||||
|
|
||||||
|
if (mode == MODE_LOAD_DA_SHIT_ALREADY) {
|
||||||
|
loadFired += 1
|
||||||
|
// to hide the "flipped skybox" artefact
|
||||||
|
batch.end()
|
||||||
|
|
||||||
|
gdxClearAndEnableBlend(.094f, .094f, .094f, 0f)
|
||||||
|
|
||||||
|
batch.begin()
|
||||||
|
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
val txt = Lang["MENU_IO_LOADING"]
|
||||||
|
App.fontGame.draw(batch, txt, (App.scr.width - App.fontGame.getWidth(txt)) / 2f, (App.scr.height - App.fontGame.lineHeight) / 2f)
|
||||||
|
|
||||||
|
if (loadFired == 2) {
|
||||||
|
LoadSavegame(UILoadGovernor.playerDisk!!, UILoadGovernor.worldDisk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mode == MODE_SELECT || mode == MODE_SAVE_DELETE) {
|
||||||
|
batch.end()
|
||||||
|
|
||||||
|
val cells = getCells()
|
||||||
|
|
||||||
|
lateinit var savePixmap: Pixmap
|
||||||
|
sliderFBO.inAction(camera as OrthographicCamera, batch) {
|
||||||
|
gdxClearAndEnableBlend(0f, 0f, 0f, 0f)
|
||||||
|
|
||||||
|
setCameraPosition(batch, camera, 0f, 0f)
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
batch.inUse {
|
||||||
|
for (index in 0 until cells.size) {
|
||||||
|
val it = cells[index]
|
||||||
|
|
||||||
|
if (App.getConfigBoolean("fx_streamerslayout"))
|
||||||
|
it.posX += uiXdiffChatOverlay
|
||||||
|
|
||||||
|
if (index in listScroll - 2 until listScroll + savesVisible + 2)
|
||||||
|
it.render(batch, camera)
|
||||||
|
|
||||||
|
if (App.getConfigBoolean("fx_streamerslayout"))
|
||||||
|
it.posX -= uiXdiffChatOverlay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
savePixmap = Pixmap.createFromFrameBuffer(0, 0, sliderFBO.width, sliderFBO.height)
|
||||||
|
savePixmap.blending = Pixmap.Blending.None
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// implement "wipe-out" by CPU-rendering (*deep exhale*)
|
||||||
|
//savePixmap.setColor(1f,1f,1f,0f)
|
||||||
|
savePixmap.setColor(0f, 0f, 0f, 0f)
|
||||||
|
savePixmap.fillRectangle(0, savePixmap.height - titleTopGradStart, savePixmap.width, titleTopGradStart)
|
||||||
|
// top grad
|
||||||
|
for (y in titleTopGradStart until titleTopGradEnd) {
|
||||||
|
val alpha = (y - titleTopGradStart).toFloat() / gradAreaHeight
|
||||||
|
for (x in 0 until savePixmap.width) {
|
||||||
|
val col = savePixmap.getPixel(x, savePixmap.height - y)
|
||||||
|
val blendAlpha = (col.and(0xFF) * alpha).roundToInt()
|
||||||
|
savePixmap.drawPixel(x, savePixmap.height - y, col.and(0xFFFFFF00.toInt()) or blendAlpha)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// bottom grad
|
||||||
|
for (y in titleBottomGradStart until titleBottomGradEnd) {
|
||||||
|
val alpha = 1f - ((y - titleBottomGradStart).toFloat() / gradAreaHeight)
|
||||||
|
for (x in 0 until savePixmap.width) {
|
||||||
|
val col = savePixmap.getPixel(x, savePixmap.height - y)
|
||||||
|
val blendAlpha = (col.and(0xFF) * alpha).roundToInt()
|
||||||
|
savePixmap.drawPixel(x, savePixmap.height - y, col.and(0xFFFFFF00.toInt()) or blendAlpha)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
savePixmap.setColor(0f, 0f, 0f, 0f)
|
||||||
|
savePixmap.fillRectangle(0, 0, savePixmap.width, height - titleBottomGradEnd + 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
setCameraPosition(batch, camera, 0f, 0f)
|
||||||
|
val saveTex = TextureRegion(Texture(savePixmap)); saveTex.flip(false, true)
|
||||||
|
batch.inUse {
|
||||||
|
batch.draw(saveTex, (width - uiWidth - 10) / 2f, 0f)
|
||||||
|
// Control help
|
||||||
|
App.fontGame.draw(batch, controlHelp, uiX.toFloat(), controlHelperY.toFloat())
|
||||||
|
}
|
||||||
|
|
||||||
|
saveTex.texture.dispose()
|
||||||
|
savePixmap.dispose()
|
||||||
|
|
||||||
|
batch.begin()
|
||||||
|
}
|
||||||
|
else if (mode == MODE_SAVE_MULTIPLE_CHOICES) {
|
||||||
|
// "The Autosave is more recent than the manual save"
|
||||||
|
Toolkit.drawTextCentered(batch, App.fontGame, Lang["GAME_MORE_RECENT_AUTOSAVE1"], Toolkit.drawWidth, 0, altSelDrawY)
|
||||||
|
Toolkit.drawTextCentered(batch, App.fontGame, Lang["GAME_MORE_RECENT_AUTOSAVE2"], Toolkit.drawWidth, 0, altSelDrawY + 24)
|
||||||
|
// Manual Save Autosave
|
||||||
|
Toolkit.drawTextCentered(batch, App.fontGame, Lang["MENU_IO_MANUAL_SAVE"], altSelHdrawW, (Toolkit.drawWidth - altSelDrawW)/2, altSelDrawY + 80)
|
||||||
|
Toolkit.drawTextCentered(batch, App.fontGame, Lang["MENU_IO_AUTOSAVE"], altSelHdrawW, Toolkit.drawWidth/2, altSelDrawY + 80)
|
||||||
|
|
||||||
|
|
||||||
|
// draw thumbnail-buttons
|
||||||
|
loadAutoThumbButton.render(batch, camera)
|
||||||
|
loadManualThumbButton.render(batch, camera)
|
||||||
|
}
|
||||||
|
else if (mode == MODE_SAVE_DAMAGED) {
|
||||||
|
Toolkit.drawTextCentered(batch, App.fontGame, Lang["ERROR_SAVE_CORRUPTED"], Toolkit.drawWidth, 0, App.scr.height / 2 - 42)
|
||||||
|
|
||||||
|
corruptedBackButton.render(batch, camera)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (mode == MODE_SELECT || mode == MODE_SAVE_DELETE || mode == MODE_SAVE_DELETE_CONFIRM) {
|
||||||
|
deleteCharacterButton.render(batch, camera)
|
||||||
|
}
|
||||||
|
if (mode == MODE_SAVE_DELETE_CONFIRM) {
|
||||||
|
buttonSelectedForDeletion?.render(batch, camera)
|
||||||
|
confirmCancelButton.render(batch, camera)
|
||||||
|
confirmDeleteButton.render(batch, camera)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == MODE_SAVE_DELETE_CONFIRM) {
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
Toolkit.drawTextCentered(batch, App.fontGame, Lang["MENU_LABEL_SAVE_WILL_BE_DELETED"], Toolkit.drawWidth, 0, titleTopGradEnd + cellInterval - 46)
|
||||||
|
Toolkit.drawTextCentered(batch, App.fontGame, Lang["MENU_LABEL_ARE_YOU_SURE"], Toolkit.drawWidth, 0, titleTopGradEnd + cellInterval + SAVE_CELL_HEIGHT + 36)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun keyDown(keycode: Int): Boolean {
|
||||||
|
if (this.isVisible && (mode == MODE_SELECT || mode == MODE_SAVE_DELETE)) {
|
||||||
|
val cells = getCells()
|
||||||
|
|
||||||
|
if ((keycode == Input.Keys.UP || keycode == App.getConfigInt("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) {
|
||||||
|
scrollFrom = listScroll
|
||||||
|
scrollTarget += 1
|
||||||
|
scrollAnimCounter = 0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||||
|
printdbg(this, "touchDown mode=$mode")
|
||||||
|
|
||||||
|
if (mode == MODE_SAVE_MULTIPLE_CHOICES) {
|
||||||
|
if (::loadAutoThumbButton.isInitialized) loadAutoThumbButton.touchDown(screenX, screenY, pointer, button)
|
||||||
|
if (::loadManualThumbButton.isInitialized) loadManualThumbButton.touchDown(screenX, screenY, pointer, button)
|
||||||
|
}
|
||||||
|
else if (mode == MODE_SELECT || mode == MODE_SAVE_DELETE) {
|
||||||
|
getCells().forEach { it.touchDown(screenX, screenY, pointer, button) }
|
||||||
|
deleteCharacterButton.touchDown(screenX, screenY, pointer, button)
|
||||||
|
}
|
||||||
|
else if (mode == MODE_SAVE_DELETE_CONFIRM) {
|
||||||
|
confirmCancelButton.touchDown(screenX, screenY, pointer, button)
|
||||||
|
confirmDeleteButton.touchDown(screenX, screenY, pointer, button)
|
||||||
|
}
|
||||||
|
else if (mode == MODE_SAVE_DAMAGED) corruptedBackButton.touchDown(screenX, screenY, pointer, button)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||||
|
if (mode == MODE_SAVE_MULTIPLE_CHOICES) {
|
||||||
|
if (::loadAutoThumbButton.isInitialized) loadAutoThumbButton.touchUp(screenX, screenY, pointer, button)
|
||||||
|
if (::loadManualThumbButton.isInitialized) loadManualThumbButton.touchUp(screenX, screenY, pointer, button)
|
||||||
|
}
|
||||||
|
else if (mode == MODE_SELECT || mode == MODE_SAVE_DELETE) {
|
||||||
|
getCells().forEach { it.touchUp(screenX, screenY, pointer, button) }
|
||||||
|
deleteCharacterButton.touchUp(screenX, screenY, pointer, button)
|
||||||
|
}
|
||||||
|
else if (mode == MODE_SAVE_DELETE_CONFIRM) {
|
||||||
|
confirmCancelButton.touchUp(screenX, screenY, pointer, button)
|
||||||
|
confirmDeleteButton.touchUp(screenX, screenY, pointer, button)
|
||||||
|
}
|
||||||
|
else if (mode == MODE_SAVE_DAMAGED) corruptedBackButton.touchUp(screenX, screenY, pointer, button)
|
||||||
|
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun scrolled(amountX: Float, amountY: Float): Boolean {
|
||||||
|
if (this.isVisible && mode == MODE_SELECT || mode == MODE_SAVE_DELETE) {
|
||||||
|
val cells = getCells()
|
||||||
|
|
||||||
|
if (amountY <= -1f && scrollTarget > 0) {
|
||||||
|
scrollFrom = listScroll
|
||||||
|
scrollTarget -= 1
|
||||||
|
scrollAnimCounter = 0f
|
||||||
|
}
|
||||||
|
else if (amountY >= 1f && scrollTarget < cells.size - savesVisible) {
|
||||||
|
scrollFrom = listScroll
|
||||||
|
scrollTarget += 1
|
||||||
|
scrollAnimCounter = 0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun endClosing(delta: Float) {
|
||||||
|
super.endClosing(delta)
|
||||||
|
listScroll = 0
|
||||||
|
scrollTarget = 0
|
||||||
|
uiScroll = 0f
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
try { shapeRenderer.dispose() } catch (e: IllegalArgumentException) {}
|
||||||
|
try { sliderFBO.dispose() } catch (e: IllegalArgumentException) {}
|
||||||
|
disposablePool.forEach {
|
||||||
|
try { it.dispose() } catch (e: GdxRuntimeException) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resize(width: Int, height: Int) {
|
||||||
|
super.resize(width, height)
|
||||||
|
scrollAreaHeight = height - 2 * App.scr.tvSafeGraphicsHeight - 64
|
||||||
|
savesVisible = (scrollAreaHeight + cellInterval) / (cellInterval + SAVE_CELL_HEIGHT)
|
||||||
|
|
||||||
|
listScroll = 0
|
||||||
|
scrollTarget = 0
|
||||||
|
uiScroll = 0f
|
||||||
|
|
||||||
|
sliderFBO.dispose()
|
||||||
|
sliderFBO = FrameBuffer(Pixmap.Format.RGBA8888, uiWidth + 10, height, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setCameraPosition(batch: SpriteBatch, camera: Camera, newX: Float, newY: Float) {
|
||||||
|
camera.position.set((-newX + App.scr.halfw).round(), (-newY + App.scr.halfh).round(), 0f)
|
||||||
|
camera.update()
|
||||||
|
batch.projectionMatrix = camera.combined
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Camera
|
|||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
import net.torvald.terrarum.App
|
import net.torvald.terrarum.App
|
||||||
|
import net.torvald.terrarum.App.printdbg
|
||||||
import net.torvald.terrarum.Second
|
import net.torvald.terrarum.Second
|
||||||
import net.torvald.terrarum.Terrarum
|
import net.torvald.terrarum.Terrarum
|
||||||
import net.torvald.terrarum.gameactors.AVKey
|
import net.torvald.terrarum.gameactors.AVKey
|
||||||
@@ -47,7 +48,7 @@ class UINewCharacter(val remoCon: UIRemoCon) : UICanvas() {
|
|||||||
private var uiLocked = false
|
private var uiLocked = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
goButton.touchDownListener = { _, _, _, _ ->
|
goButton.clickOnceListener = { _,_ ->
|
||||||
uiLocked = true
|
uiLocked = true
|
||||||
|
|
||||||
|
|
||||||
@@ -64,6 +65,7 @@ class UINewCharacter(val remoCon: UIRemoCon) : UICanvas() {
|
|||||||
|
|
||||||
|
|
||||||
val savingThread = Thread({
|
val savingThread = Thread({
|
||||||
|
printdbg(this, "Player saving thread fired")
|
||||||
|
|
||||||
disk.saveMode = 2 // auto, no quick
|
disk.saveMode = 2 // auto, no quick
|
||||||
disk.capacity = 0L
|
disk.capacity = 0L
|
||||||
@@ -79,12 +81,17 @@ class UINewCharacter(val remoCon: UIRemoCon) : UICanvas() {
|
|||||||
UILoadGovernor.playerDisk = DiskSkimmer(outFile)
|
UILoadGovernor.playerDisk = DiskSkimmer(outFile)
|
||||||
// comment above if chargen must send gamers back to the charcters list
|
// comment above if chargen must send gamers back to the charcters list
|
||||||
|
|
||||||
|
printdbg(this, "playerdisk: ${UILoadGovernor.playerDisk?.diskFile?.path}")
|
||||||
|
|
||||||
}, "TerrarumBasegameNewCharcterSaveThread")
|
}, "TerrarumBasegameNewCharcterSaveThread")
|
||||||
savingThread.start()
|
|
||||||
|
// savingThread.start()
|
||||||
|
// savingThread.join()
|
||||||
|
|
||||||
|
remoCon.openUI(UINewWorld(remoCon, savingThread)) // let UINewWorld handle the character file generation
|
||||||
}
|
}
|
||||||
backButton.touchDownListener = { _, _, _, _ ->
|
backButton.clickOnceListener = { _,_ ->
|
||||||
remoCon.openUI(UILoadDemoSavefiles(remoCon, 0))
|
remoCon.openUI(UILoadSavegame(remoCon))
|
||||||
}
|
}
|
||||||
|
|
||||||
addUIitem(nameInput)
|
addUIitem(nameInput)
|
||||||
@@ -99,7 +106,7 @@ class UINewCharacter(val remoCon: UIRemoCon) : UICanvas() {
|
|||||||
|
|
||||||
if (returnedFromChargen) {
|
if (returnedFromChargen) {
|
||||||
returnedFromChargen = false
|
returnedFromChargen = false
|
||||||
remoCon.openUI(UILoadDemoSavefiles(remoCon, 1)) // 0 to go back (Terraria's behav), set variables up and 1 to choose world
|
remoCon.openUI(UILoadSavegame(remoCon))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +114,7 @@ class UINewCharacter(val remoCon: UIRemoCon) : UICanvas() {
|
|||||||
batch.color = Color.WHITE
|
batch.color = Color.WHITE
|
||||||
// ui title
|
// ui title
|
||||||
// val titlestr = Lang["CONTEXT_WORLD_NEW"]
|
// val titlestr = Lang["CONTEXT_WORLD_NEW"]
|
||||||
// App.fontUITitle.draw(batch, titlestr, drawX + (width - App.fontGame.getWidth(titlestr)).div(2).toFloat(), titleTextPosY.toFloat())
|
// App.fontUITitle.draw(batch, titlestr, drawX + (width - App.fontUITitle.getWidth(titlestr)).div(2).toFloat(), titleTextPosY.toFloat())
|
||||||
|
|
||||||
|
|
||||||
// name/seed input labels
|
// name/seed input labels
|
||||||
|
|||||||
@@ -7,11 +7,8 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
|||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||||
import net.torvald.random.HQRNG
|
import net.torvald.random.HQRNG
|
||||||
import net.torvald.random.XXHash64
|
import net.torvald.random.XXHash64
|
||||||
import net.torvald.terrarum.App
|
import net.torvald.terrarum.*
|
||||||
import net.torvald.terrarum.App.printdbg
|
import net.torvald.terrarum.App.printdbg
|
||||||
import net.torvald.terrarum.ModMgr
|
|
||||||
import net.torvald.terrarum.Second
|
|
||||||
import net.torvald.terrarum.Terrarum
|
|
||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame.Companion.NEW_WORLD_SIZE
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame.Companion.NEW_WORLD_SIZE
|
||||||
@@ -30,6 +27,12 @@ import net.torvald.terrarum.utils.RandomWordsName
|
|||||||
*/
|
*/
|
||||||
class UINewWorld(val remoCon: UIRemoCon) : UICanvas() {
|
class UINewWorld(val remoCon: UIRemoCon) : UICanvas() {
|
||||||
|
|
||||||
|
private var newPlayerCreationThread = Thread {}
|
||||||
|
|
||||||
|
constructor(remoCon: UIRemoCon, playerCreationThread: Thread) : this(remoCon) {
|
||||||
|
newPlayerCreationThread = playerCreationThread
|
||||||
|
}
|
||||||
|
|
||||||
private val hugeTex = TextureRegion(Texture(ModMgr.getGdxFile("basegame", "gui/huge.png")))
|
private val hugeTex = TextureRegion(Texture(ModMgr.getGdxFile("basegame", "gui/huge.png")))
|
||||||
private val largeTex = TextureRegion(Texture(ModMgr.getGdxFile("basegame", "gui/large.png")))
|
private val largeTex = TextureRegion(Texture(ModMgr.getGdxFile("basegame", "gui/large.png")))
|
||||||
private val normalTex = TextureRegion(Texture(ModMgr.getGdxFile("basegame", "gui/normal.png")))
|
private val normalTex = TextureRegion(Texture(ModMgr.getGdxFile("basegame", "gui/normal.png")))
|
||||||
@@ -85,9 +88,16 @@ class UINewWorld(val remoCon: UIRemoCon) : UICanvas() {
|
|||||||
private val backButton = UIItemTextButton(this, "MENU_LABEL_BACK", drawX + (width/2 - goButtonWidth) / 2, drawY + height - 24, goButtonWidth, true, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
|
private val backButton = UIItemTextButton(this, "MENU_LABEL_BACK", drawX + (width/2 - goButtonWidth) / 2, drawY + height - 24, goButtonWidth, true, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
|
||||||
private val goButton = UIItemTextButton(this, "MENU_LABEL_CONFIRM_BUTTON", drawX + width/2 + (width/2 - goButtonWidth) / 2, drawY + height - 24, goButtonWidth, true, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
|
private val goButton = UIItemTextButton(this, "MENU_LABEL_CONFIRM_BUTTON", drawX + width/2 + (width/2 - goButtonWidth) / 2, drawY + height - 24, goButtonWidth, true, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
goButton.touchDownListener = { _, _, _, _ ->
|
goButton.clickOnceListener = { _, _ ->
|
||||||
// printdbg(this, "generate! Size=${sizeSelector.selection}, Name=${nameInput.getTextOrPlaceholder()}, Seed=${seedInput.getTextOrPlaceholder()}")
|
|
||||||
|
// after the save is complete, proceed to new world generation
|
||||||
|
newPlayerCreationThread.start()
|
||||||
|
newPlayerCreationThread.join()
|
||||||
|
|
||||||
|
|
||||||
|
printdbg(this, "generate! Size=${sizeSelector.selection}, Name=${nameInput.getTextOrPlaceholder()}, Seed=${seedInput.getTextOrPlaceholder()}")
|
||||||
|
|
||||||
val ingame = TerrarumIngame(App.batch)
|
val ingame = TerrarumIngame(App.batch)
|
||||||
val player = ReadActor.invoke(UILoadGovernor.playerDisk!!, ByteArray64Reader(UILoadGovernor.playerDisk!!.getFile(SAVEGAMEINFO)!!.bytes, Common.CHARSET)) as IngamePlayer
|
val player = ReadActor.invoke(UILoadGovernor.playerDisk!!, ByteArray64Reader(UILoadGovernor.playerDisk!!.getFile(SAVEGAMEINFO)!!.bytes, Common.CHARSET)) as IngamePlayer
|
||||||
@@ -111,8 +121,8 @@ class UINewWorld(val remoCon: UIRemoCon) : UICanvas() {
|
|||||||
App.setLoadScreen(loadScreen)
|
App.setLoadScreen(loadScreen)
|
||||||
|
|
||||||
}
|
}
|
||||||
backButton.touchDownListener = { _, _, _, _ ->
|
backButton.clickOnceListener = { _, _ ->
|
||||||
remoCon.openUI(UILoadDemoSavefiles(remoCon, 1))
|
remoCon.openUI(UILoadSavegame(remoCon))
|
||||||
}
|
}
|
||||||
|
|
||||||
addUIitem(sizeSelector)
|
addUIitem(sizeSelector)
|
||||||
@@ -131,7 +141,7 @@ class UINewWorld(val remoCon: UIRemoCon) : UICanvas() {
|
|||||||
batch.color = Color.WHITE
|
batch.color = Color.WHITE
|
||||||
// ui title
|
// ui title
|
||||||
// val titlestr = Lang["CONTEXT_WORLD_NEW"]
|
// val titlestr = Lang["CONTEXT_WORLD_NEW"]
|
||||||
// App.fontUITitle.draw(batch, titlestr, drawX + (width - App.fontGame.getWidth(titlestr)).div(2).toFloat(), titleTextPosY.toFloat())
|
// App.fontUITitle.draw(batch, titlestr, drawX + (width - App.fontUITitle.getWidth(titlestr)).div(2).toFloat(), titleTextPosY.toFloat())
|
||||||
|
|
||||||
// draw size previews
|
// draw size previews
|
||||||
val texture = tex[sizeSelector.selection.coerceAtMost(tex.lastIndex)]
|
val texture = tex[sizeSelector.selection.coerceAtMost(tex.lastIndex)]
|
||||||
|
|||||||
@@ -0,0 +1,239 @@
|
|||||||
|
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.CommonResourcePool
|
||||||
|
import net.torvald.terrarum.ceilInt
|
||||||
|
import net.torvald.terrarum.langpack.Lang
|
||||||
|
import net.torvald.terrarum.ui.*
|
||||||
|
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||||
|
import net.torvald.unicode.TIMES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2023-06-22.
|
||||||
|
*/
|
||||||
|
class UIPerformanceControlPanel(remoCon: UIRemoCon?) : UICanvas() {
|
||||||
|
|
||||||
|
|
||||||
|
private val linegap = 14
|
||||||
|
private val panelgap = 20
|
||||||
|
|
||||||
|
private val rowheight = 20 + linegap
|
||||||
|
|
||||||
|
private val h1MarginTop = 16
|
||||||
|
private val h1MarginBottom = 4
|
||||||
|
|
||||||
|
private val options = arrayOf(
|
||||||
|
arrayOf("", { Lang["MENU_OPTIONS_GAMEPLAY"] }, "h1"),
|
||||||
|
arrayOf("autosaveinterval", { Lang["MENU_OPTIONS_AUTOSAVE"] + " (${Lang["CONTEXT_TIME_MINUTE_PLURAL"]})" }, "spinnerimul,1,120,1,60000"),
|
||||||
|
arrayOf("notificationshowuptime", { Lang["MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION"] + " (${Lang["CONTEXT_TIME_SECOND_PLURAL"]})" }, "spinnerimul,2,10,1,1000"),
|
||||||
|
arrayOf("", { Lang["MENU_LABEL_JVM_DNT"] }, "h1"),
|
||||||
|
arrayOf("jvm_xmx", { Lang["MENU_OPTIONS_JVM_HEAP_MAX"] + " (GB)" }, "spinner,2,32,1"),
|
||||||
|
arrayOf("jvm_extra_cmd", { Lang["MENU_LABEL_EXTRA_JVM_ARGUMENTS"] }, "typein"),
|
||||||
|
arrayOf("", { "(${Lang["MENU_LABEL_RESTART_REQUIRED"]})" }, "p"),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val optionsYpos = IntArray(options.size + 1)
|
||||||
|
|
||||||
|
init {
|
||||||
|
CommonResourcePool.addToLoadingList("gui_hrule") {
|
||||||
|
TextureRegionPack(Gdx.files.internal("assets/graphics/gui/hrule.tga"), 216, 20)
|
||||||
|
}
|
||||||
|
CommonResourcePool.loadAll()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var akku = 0
|
||||||
|
options.forEachIndexed { index, row ->
|
||||||
|
val option = row[2]
|
||||||
|
|
||||||
|
if (index > 0 && option == "h1") {
|
||||||
|
akku += h1MarginTop
|
||||||
|
}
|
||||||
|
|
||||||
|
optionsYpos[index] = akku
|
||||||
|
|
||||||
|
akku += when (option) {
|
||||||
|
"h1" -> rowheight + h1MarginBottom
|
||||||
|
else -> rowheight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
optionsYpos[optionsYpos.lastIndex] = akku
|
||||||
|
}
|
||||||
|
override var width = 560
|
||||||
|
override var height = optionsYpos.last()
|
||||||
|
|
||||||
|
private val hrule = CommonResourcePool.getAsTextureRegionPack("gui_hrule")
|
||||||
|
|
||||||
|
private val spinnerWidth = 140
|
||||||
|
private val typeinWidth = 240
|
||||||
|
private val drawX = (Toolkit.drawWidth - width) / 2
|
||||||
|
private val drawY = (App.scr.height - height) / 2
|
||||||
|
|
||||||
|
// @return Pair of <UIItem, Init job for the item>
|
||||||
|
private fun makeButton(args: String, x: Int, y: Int, optionName: String): Pair<UIItem, (UIItem, String) -> Unit> {
|
||||||
|
return if (args.startsWith("h1") || args.startsWith("p")) {
|
||||||
|
(object : UIItem(this, x, y) {
|
||||||
|
override val width = 1
|
||||||
|
override val height = 1
|
||||||
|
override fun dispose() {}
|
||||||
|
}) to { _, _ -> }
|
||||||
|
}
|
||||||
|
else if (args.startsWith("toggle")) {
|
||||||
|
UIItemToggleButton(this, x, y, spinnerWidth, App.getConfigBoolean(optionName)) to { it: UIItem, optionStr: String ->
|
||||||
|
(it as UIItemToggleButton).clickOnceListener = { _, _ ->
|
||||||
|
it.toggle()
|
||||||
|
App.setConfig(optionStr, it.getStatus())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args.startsWith("spinner,")) {
|
||||||
|
val arg = args.split(',')
|
||||||
|
UIItemSpinner(this, x, y, App.getConfigInt(optionName), arg[1].toInt(), arg[2].toInt(), arg[3].toInt(), spinnerWidth, numberToTextFunction = { "${it.toLong()}" }) to { it: UIItem, optionStr: String ->
|
||||||
|
(it as UIItemSpinner).selectionChangeListener = {
|
||||||
|
App.setConfig(optionStr, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args.startsWith("spinnerd,")) {
|
||||||
|
val arg = args.split(',')
|
||||||
|
UIItemSpinner(this, x, y, App.getConfigDouble(optionName), arg[1].toDouble(), arg[2].toDouble(), arg[3].toDouble(), spinnerWidth, numberToTextFunction = { "${((it as Double)*100).toInt()}%" }) to { it: UIItem, optionStr: String ->
|
||||||
|
(it as UIItemSpinner).selectionChangeListener = {
|
||||||
|
App.setConfig(optionStr, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args.startsWith("spinnerimul,")) {
|
||||||
|
val arg = args.split(',')
|
||||||
|
val mult = arg[4].toInt()
|
||||||
|
UIItemSpinner(this, x, y, App.getConfigInt(optionName) / mult, arg[1].toInt(), arg[2].toInt(), arg[3].toInt(), spinnerWidth, numberToTextFunction = { "${it.toLong()}" }) to { it: UIItem, optionStr: String ->
|
||||||
|
(it as UIItemSpinner).selectionChangeListener = {
|
||||||
|
App.setConfig(optionStr, it.toInt() * mult)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args.startsWith("typeinint")) {
|
||||||
|
// val arg = args.split(',') // args: none
|
||||||
|
UIItemTextLineInput(this, x, y, spinnerWidth,
|
||||||
|
defaultValue = { "${App.getConfigInt(optionName)}" },
|
||||||
|
maxLen = InputLenCap(4, InputLenCap.CharLenUnit.CODEPOINTS),
|
||||||
|
keyFilter = { it.headkey in Input.Keys.NUM_0..Input.Keys.NUM_9 || it.headkey == Input.Keys.BACKSPACE }
|
||||||
|
) to { it: UIItem, optionStr: String ->
|
||||||
|
(it as UIItemTextLineInput).textCommitListener = {
|
||||||
|
App.setConfig(optionStr, it.toInt()) // HAXXX!!!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args.startsWith("typeinres")) {
|
||||||
|
val keyWidth = optionName.substringBefore(',')
|
||||||
|
val keyHeight = optionName.substringAfter(',')
|
||||||
|
UIItemTextLineInput(this, x, y, spinnerWidth,
|
||||||
|
defaultValue = { "${App.getConfigInt(keyWidth)}x${App.getConfigInt(keyHeight)}" },
|
||||||
|
maxLen = InputLenCap(9, InputLenCap.CharLenUnit.CODEPOINTS),
|
||||||
|
keyFilter = { it.headkey == Input.Keys.ENTER || it.headkey == Input.Keys.BACKSPACE || it.character?.matches(Regex("[0-9xX]")) == true },
|
||||||
|
alignment = UIItemTextButton.Companion.Alignment.CENTRE
|
||||||
|
) to { it: UIItem, optionStr: String ->
|
||||||
|
(it as UIItemTextLineInput).textCommitListener = { text ->
|
||||||
|
val text = text.lowercase()
|
||||||
|
if (text.matches(Regex("""[0-9]+x[0-9]+"""))) {
|
||||||
|
it.markAsNormal()
|
||||||
|
val width = text.substringBefore('x').toInt()
|
||||||
|
val height = text.substringAfter('x').toInt()
|
||||||
|
App.setConfig(keyWidth, width)
|
||||||
|
App.setConfig(keyHeight, height)
|
||||||
|
}
|
||||||
|
else it.markAsInvalid()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args.startsWith("typein")) {
|
||||||
|
//args: none
|
||||||
|
UIItemTextLineInput(this, x, y, typeinWidth, defaultValue = { App.getConfigString(optionName) }) to { it: UIItem, optionStr: String ->
|
||||||
|
(it as UIItemTextLineInput).textCommitListener = {
|
||||||
|
App.setConfig(optionStr, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else throw IllegalArgumentException(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val optionControllers: List<Pair<UIItem, (UIItem, String) -> Unit>> = options.mapIndexed { index, strings ->
|
||||||
|
makeButton(options[index][2] as String,
|
||||||
|
drawX + width / 2 + panelgap,
|
||||||
|
drawY - 2 + optionsYpos[index],
|
||||||
|
options[index][0] as String
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
optionControllers.forEachIndexed { i, it ->
|
||||||
|
it.second.invoke(it.first, options[i][0] as String)
|
||||||
|
addUIitem(it.first)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateUI(delta: Float) {
|
||||||
|
uiItems.forEach { it.update(delta) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||||
|
/*batch.color = Toolkit.Theme.COL_INACTIVE
|
||||||
|
Toolkit.drawBoxBorder(batch, drawX, drawY, width, height)
|
||||||
|
|
||||||
|
batch.color = CELL_COL
|
||||||
|
Toolkit.fillArea(batch, drawX, drawY, width, height)*/
|
||||||
|
|
||||||
|
options.forEachIndexed { index, strings ->
|
||||||
|
val mode = strings[2]
|
||||||
|
|
||||||
|
val font = if (mode == "h1") App.fontUITitle else App.fontGame
|
||||||
|
|
||||||
|
val label = (strings[1] as () -> String).invoke()
|
||||||
|
val labelWidth = font.getWidth(label)
|
||||||
|
batch.color = when (mode) {
|
||||||
|
"h1" -> Toolkit.Theme.COL_MOUSE_UP
|
||||||
|
"p" -> Color.LIGHT_GRAY
|
||||||
|
else -> Color.WHITE
|
||||||
|
}
|
||||||
|
|
||||||
|
val xpos = if (mode == "p" || mode == "h1")
|
||||||
|
drawX + (width - labelWidth)/2 // centre-aligned
|
||||||
|
else
|
||||||
|
drawX + width/2 - panelgap - labelWidth // right aligned at the middle of the panel, offsetted by panelgap
|
||||||
|
|
||||||
|
font.draw(batch, label, xpos.toFloat(), drawY + optionsYpos[index] - 2f)
|
||||||
|
|
||||||
|
// draw hrule
|
||||||
|
if (mode == "h1") {
|
||||||
|
val ruleWidth = ((width - 24 - labelWidth) / 2).toFloat()
|
||||||
|
batch.draw(hrule.get(0,0), xpos - 24f - ruleWidth, drawY + optionsYpos[index].toFloat(), ruleWidth, hrule.tileH.toFloat())
|
||||||
|
batch.draw(hrule.get(0,1), xpos + 24f + labelWidth, drawY + optionsYpos[index].toFloat(), ruleWidth, hrule.tileH.toFloat())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uiItems.forEach { it.render(batch, camera) }
|
||||||
|
|
||||||
|
if (App.getConfigBoolean("fx_streamerslayout")) {
|
||||||
|
val xstart = App.scr.width - App.scr.chatWidth
|
||||||
|
|
||||||
|
batch.color = Color(0x00f8ff_40)
|
||||||
|
Toolkit.fillArea(batch, xstart + 1, 1, App.scr.chatWidth - 2, App.scr.height - 2)
|
||||||
|
|
||||||
|
batch.color = Toolkit.Theme.COL_MOUSE_UP
|
||||||
|
Toolkit.drawBoxBorder(batch, xstart + 1, 1, App.scr.chatWidth - 2, App.scr.height - 2)
|
||||||
|
|
||||||
|
val overlayResTxt = "${(App.scr.chatWidth * App.scr.magn).ceilInt()}$TIMES${App.scr.windowH}"
|
||||||
|
|
||||||
|
App.fontGame.draw(batch, overlayResTxt,
|
||||||
|
(xstart + (App.scr.chatWidth - App.fontGame.getWidth(overlayResTxt)) / 2).toFloat(),
|
||||||
|
((App.scr.height - App.fontGame.lineHeight) / 2).toFloat()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,7 +49,7 @@ class UIQuickslotPie : UICanvas() {
|
|||||||
// update controls
|
// update controls
|
||||||
if (handler.isOpened || handler.isOpening) {
|
if (handler.isOpened || handler.isOpening) {
|
||||||
val cursorPos = Vector2(Terrarum.mouseScreenX.toDouble(), Terrarum.mouseScreenY.toDouble())
|
val cursorPos = Vector2(Terrarum.mouseScreenX.toDouble(), Terrarum.mouseScreenY.toDouble())
|
||||||
val centre = Vector2(Toolkit.drawWidth / 2.0, App.scr.halfh.toDouble())
|
val centre = Vector2(Toolkit.hdrawWidth.toDouble(), App.scr.halfh.toDouble())
|
||||||
val deg = -(centre - cursorPos).direction.toFloat()
|
val deg = -(centre - cursorPos).direction.toFloat()
|
||||||
|
|
||||||
selection = Math.round(deg * slotCount / FastMath.TWO_PI)
|
selection = Math.round(deg * slotCount / FastMath.TWO_PI)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import net.torvald.terrarum.gameactors.AVKey
|
|||||||
import net.torvald.terrarum.gameitems.GameItem
|
import net.torvald.terrarum.gameitems.GameItem
|
||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory
|
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory
|
||||||
|
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.getWidthOfCells
|
||||||
import net.torvald.terrarum.ui.Toolkit
|
import net.torvald.terrarum.ui.Toolkit
|
||||||
import net.torvald.terrarum.ui.UICanvas
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
import net.torvald.unicode.getKeycapPC
|
import net.torvald.unicode.getKeycapPC
|
||||||
@@ -23,7 +24,7 @@ internal class UIStorageChest : UICanvas(
|
|||||||
lateinit var chestInventory: FixtureInventory
|
lateinit var chestInventory: FixtureInventory
|
||||||
lateinit var chestNameFun: () -> String
|
lateinit var chestNameFun: () -> String
|
||||||
|
|
||||||
override var width = App.scr.width
|
override var width = Toolkit.drawWidth
|
||||||
override var height = App.scr.height
|
override var height = App.scr.height
|
||||||
|
|
||||||
private val negotiator = object : InventoryTransactionNegotiator() {
|
private val negotiator = object : InventoryTransactionNegotiator() {
|
||||||
@@ -49,12 +50,12 @@ internal class UIStorageChest : UICanvas(
|
|||||||
private var encumbrancePerc = 0f
|
private var encumbrancePerc = 0f
|
||||||
private var isEncumbered = false
|
private var isEncumbered = false
|
||||||
|
|
||||||
private var halfSlotOffset = (UIItemInventoryElemSimple.height + UIItemInventoryItemGrid.listGap) / 2
|
private var halfSlotOffset = (UIItemInventoryElemSimple.height + UIItemInventoryItemGrid.listGap * 2) / 2
|
||||||
|
|
||||||
init {
|
init {
|
||||||
catBar = UIItemInventoryCatBar(
|
catBar = UIItemInventoryCatBar(
|
||||||
this,
|
this,
|
||||||
(App.scr.width - UIInventoryFull.catBarWidth) / 2,
|
(width - UIInventoryFull.catBarWidth) / 2,
|
||||||
42 - UIInventoryFull.YPOS_CORRECTION + (App.scr.height - UIInventoryFull.internalHeight) / 2,
|
42 - UIInventoryFull.YPOS_CORRECTION + (App.scr.height - UIInventoryFull.internalHeight) / 2,
|
||||||
UIInventoryFull.internalWidth,
|
UIInventoryFull.internalWidth,
|
||||||
UIInventoryFull.catBarWidth,
|
UIInventoryFull.catBarWidth,
|
||||||
@@ -65,42 +66,46 @@ internal class UIStorageChest : UICanvas(
|
|||||||
this,
|
this,
|
||||||
catBar,
|
catBar,
|
||||||
{ getFixtureInventory() },
|
{ getFixtureInventory() },
|
||||||
UIInventoryFull.INVENTORY_CELLS_OFFSET_X() - halfSlotOffset,
|
Toolkit.hdrawWidth - getWidthOfCells(6) - halfSlotOffset,
|
||||||
UIInventoryFull.INVENTORY_CELLS_OFFSET_Y(),
|
UIInventoryFull.INVENTORY_CELLS_OFFSET_Y(),
|
||||||
6, UIInventoryFull.CELLS_VRT,
|
6, UIInventoryFull.CELLS_VRT,
|
||||||
drawScrollOnRightside = false,
|
drawScrollOnRightside = false,
|
||||||
drawWallet = false,
|
drawWallet = false,
|
||||||
keyDownFun = { _, _, _, _, _ -> Unit },
|
keyDownFun = { _, _, _, _, _ -> Unit },
|
||||||
touchDownFun = { gameItem, amount, _, _, _ ->
|
touchDownFun = { gameItem, amount, button, _, _ ->
|
||||||
if (gameItem != null) {
|
if (button == App.getConfigInt("config_mouseprimary")) {
|
||||||
negotiator.reject(getFixtureInventory(), getPlayerInventory(), gameItem, amount)
|
if (gameItem != null) {
|
||||||
|
negotiator.reject(getFixtureInventory(), getPlayerInventory(), gameItem, amount)
|
||||||
|
}
|
||||||
|
itemListUpdate()
|
||||||
}
|
}
|
||||||
itemListUpdate()
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
// make grid mode buttons work together
|
// make grid mode buttons work together
|
||||||
itemListChest.gridModeButtons[0].touchDownListener = { _,_,_,_ -> setCompact(false) }
|
itemListChest.navRemoCon.listButtonListener = { _,_ -> setCompact(false) }
|
||||||
itemListChest.gridModeButtons[1].touchDownListener = { _,_,_,_ -> setCompact(true) }
|
itemListChest.navRemoCon.gridButtonListener = { _,_ -> setCompact(true) }
|
||||||
|
|
||||||
itemListPlayer = UIItemInventoryItemGrid(
|
itemListPlayer = UIItemInventoryItemGrid(
|
||||||
this,
|
this,
|
||||||
catBar,
|
catBar,
|
||||||
{ INGAME.actorNowPlaying!!.inventory }, // literally a player's inventory
|
{ INGAME.actorNowPlaying!!.inventory }, // literally a player's inventory
|
||||||
UIInventoryFull.INVENTORY_CELLS_OFFSET_X() - halfSlotOffset + (UIItemInventoryItemGrid.listGap + UIItemInventoryElemWide.height) * 7,
|
Toolkit.hdrawWidth + halfSlotOffset,
|
||||||
UIInventoryFull.INVENTORY_CELLS_OFFSET_Y(),
|
UIInventoryFull.INVENTORY_CELLS_OFFSET_Y(),
|
||||||
6, UIInventoryFull.CELLS_VRT,
|
6, UIInventoryFull.CELLS_VRT,
|
||||||
drawScrollOnRightside = true,
|
drawScrollOnRightside = true,
|
||||||
drawWallet = false,
|
drawWallet = false,
|
||||||
keyDownFun = { _, _, _, _, _ -> Unit },
|
keyDownFun = { _, _, _, _, _ -> Unit },
|
||||||
touchDownFun = { gameItem, amount, _, _, _ ->
|
touchDownFun = { gameItem, amount, button, _, _ ->
|
||||||
if (gameItem != null) {
|
if (button == App.getConfigInt("config_mouseprimary")) {
|
||||||
negotiator.accept(getPlayerInventory(), getFixtureInventory(), gameItem, amount)
|
if (gameItem != null) {
|
||||||
|
negotiator.accept(getPlayerInventory(), getFixtureInventory(), gameItem, amount)
|
||||||
|
}
|
||||||
|
itemListUpdate()
|
||||||
}
|
}
|
||||||
itemListUpdate()
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
itemListPlayer.gridModeButtons[0].touchDownListener = { _,_,_,_ -> setCompact(false) }
|
itemListPlayer.navRemoCon.listButtonListener = { _,_ -> setCompact(false) }
|
||||||
itemListPlayer.gridModeButtons[1].touchDownListener = { _,_,_,_ -> setCompact(true) }
|
itemListPlayer.navRemoCon.gridButtonListener = { _,_ -> setCompact(true) }
|
||||||
|
|
||||||
handler.allowESCtoClose = true
|
handler.allowESCtoClose = true
|
||||||
|
|
||||||
@@ -132,14 +137,14 @@ internal class UIStorageChest : UICanvas(
|
|||||||
|
|
||||||
private fun setCompact(yes: Boolean) {
|
private fun setCompact(yes: Boolean) {
|
||||||
itemListChest.isCompactMode = yes
|
itemListChest.isCompactMode = yes
|
||||||
itemListChest.gridModeButtons[0].highlighted = !yes
|
itemListChest.navRemoCon.gridModeButtons[0].highlighted = !yes
|
||||||
itemListChest.gridModeButtons[1].highlighted = yes
|
itemListChest.navRemoCon.gridModeButtons[1].highlighted = yes
|
||||||
itemListChest.itemPage = 0
|
itemListChest.itemPage = 0
|
||||||
itemListChest.rebuild(catBar.catIconsMeaning[catBar.selectedIcon])
|
itemListChest.rebuild(catBar.catIconsMeaning[catBar.selectedIcon])
|
||||||
|
|
||||||
itemListPlayer.isCompactMode = yes
|
itemListPlayer.isCompactMode = yes
|
||||||
itemListPlayer.gridModeButtons[0].highlighted = !yes
|
itemListPlayer.navRemoCon.gridModeButtons[0].highlighted = !yes
|
||||||
itemListPlayer.gridModeButtons[1].highlighted = yes
|
itemListPlayer.navRemoCon.gridModeButtons[1].highlighted = yes
|
||||||
itemListPlayer.itemPage = 0
|
itemListPlayer.itemPage = 0
|
||||||
itemListPlayer.rebuild(catBar.catIconsMeaning[catBar.selectedIcon])
|
itemListPlayer.rebuild(catBar.catIconsMeaning[catBar.selectedIcon])
|
||||||
|
|
||||||
@@ -161,7 +166,7 @@ internal class UIStorageChest : UICanvas(
|
|||||||
if (openingClickLatched && !Terrarum.mouseDown) openingClickLatched = false
|
if (openingClickLatched && !Terrarum.mouseDown) openingClickLatched = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private val thisOffsetX = UIInventoryFull.INVENTORY_CELLS_OFFSET_X() - halfSlotOffset
|
private val thisOffsetX = Toolkit.hdrawWidth - getWidthOfCells(6) - halfSlotOffset
|
||||||
private val thisOffsetX2 = thisOffsetX + (UIItemInventoryItemGrid.listGap + UIItemInventoryElemWide.height) * 7
|
private val thisOffsetX2 = thisOffsetX + (UIItemInventoryItemGrid.listGap + UIItemInventoryElemWide.height) * 7
|
||||||
private val thisOffsetY = UIInventoryFull.INVENTORY_CELLS_OFFSET_Y()
|
private val thisOffsetY = UIInventoryFull.INVENTORY_CELLS_OFFSET_Y()
|
||||||
private val cellsWidth = (UIItemInventoryItemGrid.listGap + UIItemInventoryElemWide.height) * 6 - UIItemInventoryItemGrid.listGap
|
private val cellsWidth = (UIItemInventoryItemGrid.listGap + UIItemInventoryElemWide.height) * 6 - UIItemInventoryItemGrid.listGap
|
||||||
@@ -174,7 +179,7 @@ internal class UIStorageChest : UICanvas(
|
|||||||
|
|
||||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||||
// background fill
|
// background fill
|
||||||
UIInventoryFull.drawBackground(batch, handler.opacity)
|
UIInventoryFull.drawBackground(batch, 1f)
|
||||||
|
|
||||||
// UI items
|
// UI items
|
||||||
batch.color = Color.WHITE
|
batch.color = Color.WHITE
|
||||||
@@ -232,19 +237,23 @@ internal class UIStorageChest : UICanvas(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun doOpening(delta: Float) {
|
override fun doOpening(delta: Float) {
|
||||||
|
super.doOpening(delta)
|
||||||
INGAME.pause()
|
INGAME.pause()
|
||||||
INGAME.setTooltipMessage(null)
|
INGAME.setTooltipMessage(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun doClosing(delta: Float) {
|
override fun doClosing(delta: Float) {
|
||||||
|
super.doClosing(delta)
|
||||||
INGAME.resume()
|
INGAME.resume()
|
||||||
INGAME.setTooltipMessage(null)
|
INGAME.setTooltipMessage(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun endOpening(delta: Float) {
|
override fun endOpening(delta: Float) {
|
||||||
|
super.endOpening(delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun endClosing(delta: Float) {
|
override fun endClosing(delta: Float) {
|
||||||
|
super.endClosing(delta)
|
||||||
UIItemInventoryItemGrid.tooltipShowing.clear()
|
UIItemInventoryItemGrid.tooltipShowing.clear()
|
||||||
INGAME.setTooltipMessage(null) // required!
|
INGAME.setTooltipMessage(null) // required!
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ class UITitleModules(val remoCon: UIRemoCon) : UICanvas() {
|
|||||||
savegamesCount += 1
|
savegamesCount += 1
|
||||||
}
|
}
|
||||||
catch (e: Throwable) {
|
catch (e: Throwable) {
|
||||||
System.err.println("[UILoadDemoSavefiles] Error while loading module info for '$s'")
|
System.err.println("[UITitleModules] Error while loading module info for '$s'")
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,7 +192,7 @@ class UITitleModules(val remoCon: UIRemoCon) : UICanvas() {
|
|||||||
// draw texts
|
// draw texts
|
||||||
val loadGameTitleStr = Lang["MENU_MODULES"]// + "$EMDASH$hash"
|
val loadGameTitleStr = Lang["MENU_MODULES"]// + "$EMDASH$hash"
|
||||||
// "Game Load"
|
// "Game Load"
|
||||||
App.fontUITitle.draw(batch, loadGameTitleStr, (width - App.fontGame.getWidth(loadGameTitleStr)).div(2).toFloat(), titleTextPosY.toFloat())
|
App.fontUITitle.draw(batch, loadGameTitleStr, (width - App.fontUITitle.getWidth(loadGameTitleStr)).div(2).toFloat(), titleTextPosY.toFloat())
|
||||||
// Control help
|
// Control help
|
||||||
App.fontGame.draw(batch, controlHelp, uiX.toFloat(), controlHelperY.toFloat())
|
App.fontGame.draw(batch, controlHelp, uiX.toFloat(), controlHelperY.toFloat())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,12 +12,13 @@ object UITitleRemoConYaml {
|
|||||||
* The class must be the UICanvas
|
* The class must be the UICanvas
|
||||||
*/
|
*/
|
||||||
val menuBase = """
|
val menuBase = """
|
||||||
- MENU_MODE_SINGLEPLAYER : net.torvald.terrarum.modulebasegame.ui.UILoadDemoSavefiles
|
- MENU_MODE_SINGLEPLAYER : net.torvald.terrarum.modulebasegame.ui.UILoadSavegame
|
||||||
- MENU_OPTIONS
|
- MENU_OPTIONS
|
||||||
- MENU_LABEL_GRAPHICS : net.torvald.terrarum.modulebasegame.ui.UIGraphicsControlPanel
|
- MENU_LABEL_GRAPHICS : net.torvald.terrarum.modulebasegame.ui.UIGraphicsControlPanel
|
||||||
- MENU_OPTIONS_CONTROLS : net.torvald.terrarum.modulebasegame.ui.UIKeyboardControlPanel
|
- MENU_OPTIONS_CONTROLS : net.torvald.terrarum.modulebasegame.ui.UIKeyboardControlPanel
|
||||||
- MENU_LABEL_IME : net.torvald.terrarum.modulebasegame.ui.UIIMEConfig
|
- MENU_LABEL_IME : net.torvald.terrarum.modulebasegame.ui.UIIMEConfig
|
||||||
- MENU_LABEL_LANGUAGE : net.torvald.terrarum.modulebasegame.ui.UITitleLanguage
|
- MENU_LABEL_LANGUAGE : net.torvald.terrarum.modulebasegame.ui.UITitleLanguage
|
||||||
|
- GAME_GENRE_MISC : net.torvald.terrarum.modulebasegame.ui.UIPerformanceControlPanel
|
||||||
- MENU_MODULES : net.torvald.terrarum.ModOptionsHost
|
- MENU_MODULES : net.torvald.terrarum.ModOptionsHost
|
||||||
- MENU_LABEL_RETURN+WRITETOCONFIG
|
- MENU_LABEL_RETURN+WRITETOCONFIG
|
||||||
- MENU_MODULES : net.torvald.terrarum.modulebasegame.ui.UITitleModules
|
- MENU_MODULES : net.torvald.terrarum.modulebasegame.ui.UITitleModules
|
||||||
@@ -25,6 +26,7 @@ object UITitleRemoConYaml {
|
|||||||
- MENU_LABEL_CREDITS
|
- MENU_LABEL_CREDITS
|
||||||
- MENU_LABEL_COPYRIGHT : net.torvald.terrarum.modulebasegame.ui.UITitleCredits
|
- MENU_LABEL_COPYRIGHT : net.torvald.terrarum.modulebasegame.ui.UITitleCredits
|
||||||
- MENU_CREDIT_GPL_DNT : net.torvald.terrarum.modulebasegame.ui.UITitleGPL3
|
- MENU_CREDIT_GPL_DNT : net.torvald.terrarum.modulebasegame.ui.UITitleGPL3
|
||||||
|
- MENU_LABEL_SYSTEM_INFO : net.torvald.terrarum.modulebasegame.ui.UISystemInfo
|
||||||
- MENU_LABEL_RETURN
|
- MENU_LABEL_RETURN
|
||||||
- MENU_LABEL_QUIT
|
- MENU_LABEL_QUIT
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -43,4 +43,5 @@ open class UITitleWallOfText(private val text: List<String>) : UICanvas() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class UITitleCredits(val remoCon: UIRemoCon) : UITitleWallOfText(CreditSingleton.credit)
|
class UITitleCredits(val remoCon: UIRemoCon) : UITitleWallOfText(CreditSingleton.credit)
|
||||||
class UITitleGPL3(val remoCon: UIRemoCon) : UITitleWallOfText(CreditSingleton.gpl3)
|
class UITitleGPL3(val remoCon: UIRemoCon) : UITitleWallOfText(CreditSingleton.gpl3)
|
||||||
|
class UISystemInfo(val remoCon: UIRemoCon) : UITitleWallOfText(CreditSingleton.systeminfo)
|
||||||
@@ -56,10 +56,11 @@ class UITooltip : UICanvas() {
|
|||||||
batch.color = tooltipBackCol
|
batch.color = tooltipBackCol
|
||||||
|
|
||||||
Toolkit.drawBaloon(batch,
|
Toolkit.drawBaloon(batch,
|
||||||
tooltipX - textMarginX,
|
tooltipX - textMarginX,
|
||||||
tooltipY,
|
tooltipY,
|
||||||
tooltipW,
|
tooltipW,
|
||||||
font.lineHeight * msgBuffer.size
|
font.lineHeight * msgBuffer.size,
|
||||||
|
Notification.OPACITY
|
||||||
)
|
)
|
||||||
|
|
||||||
batch.color = tooltipForeCol
|
batch.color = tooltipForeCol
|
||||||
|
|||||||
@@ -3,18 +3,22 @@ package net.torvald.terrarum.modulebasegame.ui
|
|||||||
import com.badlogic.gdx.graphics.Camera
|
import com.badlogic.gdx.graphics.Camera
|
||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
|
import com.jme3.math.FastMath
|
||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
import net.torvald.terrarum.gameactors.AVKey
|
import net.torvald.terrarum.gameactors.AVKey
|
||||||
|
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
|
||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
|
import net.torvald.terrarum.modulebasegame.gameactors.FixtureWorldPortal
|
||||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVENTORY_CELLS_OFFSET_Y
|
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVENTORY_CELLS_OFFSET_Y
|
||||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.YPOS_CORRECTION
|
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.YPOS_CORRECTION
|
||||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.drawBackground
|
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.drawBackground
|
||||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.internalHeight
|
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.internalHeight
|
||||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.internalWidth
|
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.internalWidth
|
||||||
|
import net.torvald.terrarum.serialise.toAscii85
|
||||||
import net.torvald.terrarum.ui.*
|
import net.torvald.terrarum.ui.*
|
||||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||||
import net.torvald.unicode.getKeycapConsole
|
|
||||||
import net.torvald.unicode.getKeycapPC
|
import net.torvald.unicode.getKeycapPC
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Structure:
|
* Structure:
|
||||||
@@ -34,60 +38,45 @@ class UIWorldPortal : UICanvas(
|
|||||||
override var width: Int = Toolkit.drawWidth
|
override var width: Int = Toolkit.drawWidth
|
||||||
override var height: Int = App.scr.height
|
override var height: Int = App.scr.height
|
||||||
|
|
||||||
|
internal lateinit var host: FixtureWorldPortal
|
||||||
|
|
||||||
|
|
||||||
val controlHelpHeight = App.fontGame.lineHeight
|
val controlHelpHeight = App.fontGame.lineHeight
|
||||||
|
|
||||||
private var panelTransitionLocked = false
|
|
||||||
|
|
||||||
fun lockTransition() {
|
|
||||||
panelTransitionLocked = true
|
|
||||||
}
|
|
||||||
fun unlockTransition() {
|
|
||||||
panelTransitionLocked = false
|
|
||||||
}
|
|
||||||
fun requestTransition(target: Int) = transitionPanel.requestTransition(target)
|
|
||||||
|
|
||||||
|
|
||||||
val catBar = UIItemWorldPortalTopBar(
|
|
||||||
this,
|
|
||||||
0,
|
|
||||||
42 - YPOS_CORRECTION + (App.scr.height - internalHeight) / 2,
|
|
||||||
) { i -> if (!panelTransitionLocked) requestTransition(i) }
|
|
||||||
|
|
||||||
|
|
||||||
private val SP = "\u3000 "
|
private val SP = "\u3000 "
|
||||||
val portalListingControlHelp: String
|
val portalListingControlHelp: String
|
||||||
get() = if (App.environment == RunningEnvironment.PC)
|
get() = if (App.environment == RunningEnvironment.PC)
|
||||||
"${getKeycapPC(App.getConfigInt("control_key_up"))}${getKeycapPC(App.getConfigInt("control_key_down"))}" +
|
"${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||||
" ${Lang["MENU_CONTROLS_SCROLL"]}" +
|
|
||||||
"$SP${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}"
|
|
||||||
else
|
else
|
||||||
"${getKeycapConsole('R')} ${Lang["MENU_CONTROLS_SCROLL"]}" +
|
"${App.gamepadLabelStart} ${Lang["GAME_ACTION_CLOSE"]}" +
|
||||||
"$SP${App.gamepadLabelStart} ${Lang["GAME_ACTION_CLOSE"]}" +
|
|
||||||
"$SP${App.gamepadLabelLT} ${Lang["GAME_WORLD_SEARCH"]}" +
|
"$SP${App.gamepadLabelLT} ${Lang["GAME_WORLD_SEARCH"]}" +
|
||||||
"$SP${App.gamepadLabelRT} ${Lang["GAME_INVENTORY"]}"
|
"$SP${App.gamepadLabelRT} ${Lang["GAME_INVENTORY"]}"
|
||||||
|
|
||||||
|
|
||||||
private val transitionalSearch = UIWorldPortalSearch(this)
|
val transitionalSearch = UIWorldPortalSearch(this)
|
||||||
private val transitionalListing = UIWorldPortalListing(this)
|
val transitionalListing = UIWorldPortalListing(this)
|
||||||
private val transitionalCargo = UIWorldPortalCargo(this)
|
// val transitionalCargo = UIWorldPortalCargo(this)
|
||||||
private val transitionPanel = UIItemHorizontalFadeSlide(
|
private val transitionPanel = UIItemHorizontalFadeSlide(
|
||||||
this,
|
this,
|
||||||
(width - internalWidth) / 2,
|
(width - internalWidth) / 2,
|
||||||
INVENTORY_CELLS_OFFSET_Y(),
|
INVENTORY_CELLS_OFFSET_Y(),
|
||||||
width,
|
width,
|
||||||
App.scr.height,
|
App.scr.height,
|
||||||
1f,
|
0f,
|
||||||
transitionalSearch, transitionalListing, transitionalCargo
|
transitionalListing, transitionalSearch
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by:
|
||||||
|
* - "Search" button on UIWorldPortalListing
|
||||||
|
* - "Cancel" button on UIWorldPortalSearch
|
||||||
|
*/
|
||||||
|
fun requestTransition(target: Int) = transitionPanel.requestTransition(target)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
addUIitem(catBar)
|
|
||||||
addUIitem(transitionPanel)
|
addUIitem(transitionPanel)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal var xEnd = (width + internalWidth).div(2).toFloat()
|
internal var xEnd = (width + internalWidth).div(2).toFloat()
|
||||||
@@ -99,57 +88,133 @@ class UIWorldPortal : UICanvas(
|
|||||||
|
|
||||||
|
|
||||||
override fun updateUI(delta: Float) {
|
override fun updateUI(delta: Float) {
|
||||||
|
transitionPanel.update(delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||||
drawBackground(batch, handler.opacity)
|
drawBackground(batch, 1f)
|
||||||
|
|
||||||
// UI items
|
// UI items
|
||||||
catBar.render(batch, camera)
|
|
||||||
transitionPanel.render(batch, camera)
|
transitionPanel.render(batch, camera)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addWorldToPlayersDict(uuid: UUID) {
|
||||||
|
val uuidstr = uuid.toAscii85()
|
||||||
|
INGAME.actorNowPlaying?.let {
|
||||||
|
val avList = (it.actorValue.getAsString(AVKey.WORLD_PORTAL_DICT) ?: "").split(',').filter { it.isNotBlank() }.toMutableList()
|
||||||
|
if (!avList.contains(uuidstr)) {
|
||||||
|
avList.add(uuidstr)
|
||||||
|
it.actorValue[AVKey.WORLD_PORTAL_DICT] = avList.joinToString(",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cleanUpWorldDict() {
|
||||||
|
// remove dupes, etc
|
||||||
|
INGAME.actorNowPlaying?.let {
|
||||||
|
val avList = (it.actorValue.getAsString(AVKey.WORLD_PORTAL_DICT) ?: "").split(',').filter { it.isNotBlank() }.toSet()
|
||||||
|
it.actorValue[AVKey.WORLD_PORTAL_DICT] = avList.joinToString(",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun show() {
|
override fun show() {
|
||||||
super.show()
|
super.show()
|
||||||
|
transitionPanel.forcePosition(0)
|
||||||
transitionPanel.show()
|
transitionPanel.show()
|
||||||
INGAME.setTooltipMessage(null)
|
INGAME.setTooltipMessage(null)
|
||||||
|
|
||||||
|
// add current world to the player's worldportaldict
|
||||||
|
addWorldToPlayersDict(INGAME.world.worldIndex)
|
||||||
|
cleanUpWorldDict()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hide() {
|
||||||
|
transitionPanel.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
catBar.dispose()
|
transitionPanel.dispose()
|
||||||
}
|
|
||||||
|
|
||||||
fun resetUI() {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun doOpening(delta: Float) {
|
override fun doOpening(delta: Float) {
|
||||||
super.doOpening(delta)
|
super.doOpening(delta)
|
||||||
resetUI()
|
transitionPanel.uis.forEach { it.opacity = FastMath.pow(opacity, 0.5f) }
|
||||||
INGAME.pause()
|
INGAME.pause()
|
||||||
INGAME.setTooltipMessage(null)
|
INGAME.setTooltipMessage(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun doClosing(delta: Float) {
|
override fun doClosing(delta: Float) {
|
||||||
super.doClosing(delta)
|
super.doClosing(delta)
|
||||||
|
transitionPanel.uis.forEach { it.opacity = FastMath.pow(opacity, 0.5f) }
|
||||||
INGAME.resume()
|
INGAME.resume()
|
||||||
INGAME.setTooltipMessage(null)
|
INGAME.setTooltipMessage(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun endOpening(delta: Float) {
|
override fun endOpening(delta: Float) {
|
||||||
super.endOpening(delta)
|
super.endOpening(delta)
|
||||||
|
transitionPanel.uis.forEach { it.opacity = FastMath.pow(opacity, 0.5f) }
|
||||||
UIItemInventoryItemGrid.tooltipShowing.clear()
|
UIItemInventoryItemGrid.tooltipShowing.clear()
|
||||||
INGAME.setTooltipMessage(null) // required!
|
INGAME.setTooltipMessage(null) // required!
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun endClosing(delta: Float) {
|
override fun endClosing(delta: Float) {
|
||||||
super.endClosing(delta)
|
super.endClosing(delta)
|
||||||
resetUI()
|
transitionPanel.uis.forEach { it.opacity = FastMath.pow(opacity, 0.5f) }
|
||||||
UIItemInventoryItemGrid.tooltipShowing.clear()
|
UIItemInventoryItemGrid.tooltipShowing.clear()
|
||||||
INGAME.setTooltipMessage(null) // required!
|
INGAME.setTooltipMessage(null) // required!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun inputStrobed(e: TerrarumKeyboardEvent) {
|
||||||
|
super.inputStrobed(e)
|
||||||
|
transitionPanel.uis.forEach { it.inputStrobed(e) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
|
||||||
|
super.touchDragged(screenX, screenY, pointer)
|
||||||
|
transitionPanel.uis.forEach { it.touchDragged(screenX, screenY, pointer) }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||||
|
super.touchDown(screenX, screenY, pointer, button)
|
||||||
|
transitionPanel.uis.forEach { it.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)
|
||||||
|
transitionPanel.uis.forEach { it.touchUp(screenX, screenY, pointer, button) }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun scrolled(amountX: Float, amountY: Float): Boolean {
|
||||||
|
super.scrolled(amountX, amountY)
|
||||||
|
transitionPanel.uis.forEach { it.scrolled(amountX, amountY) }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun keyDown(keycode: Int): Boolean {
|
||||||
|
super.keyDown(keycode)
|
||||||
|
transitionPanel.uis.forEach { it.keyDown(keycode) }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun keyUp(keycode: Int): Boolean {
|
||||||
|
super.keyUp(keycode)
|
||||||
|
transitionPanel.uis.forEach { it.keyUp(keycode) }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun keyTyped(character: Char): Boolean {
|
||||||
|
super.keyTyped(character)
|
||||||
|
transitionPanel.uis.forEach { it.keyTyped(character) }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resize(width: Int, height: Int) {
|
||||||
|
super.resize(width, height)
|
||||||
|
transitionPanel.uis.forEach { it.resize(width, height) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UIItemWorldPortalTopBar(
|
class UIItemWorldPortalTopBar(
|
||||||
@@ -171,7 +236,7 @@ class UIItemWorldPortalTopBar(
|
|||||||
|
|
||||||
private val genericIcons: TextureRegionPack = CommonResourcePool.getAsTextureRegionPack("inventory_category")
|
private val genericIcons: TextureRegionPack = CommonResourcePool.getAsTextureRegionPack("inventory_category")
|
||||||
private val icons = CommonResourcePool.getAsTextureRegionPack("terrarum-basegame-worldportalicons")
|
private val icons = CommonResourcePool.getAsTextureRegionPack("terrarum-basegame-worldportalicons")
|
||||||
private val catIconImages = listOf(
|
/*private val catIconImages = listOf(
|
||||||
icons.get(0, 0),
|
icons.get(0, 0),
|
||||||
genericIcons.get(16,0),
|
genericIcons.get(16,0),
|
||||||
icons.get(1, 0),
|
icons.get(1, 0),
|
||||||
@@ -182,15 +247,21 @@ class UIItemWorldPortalTopBar(
|
|||||||
"CONTEXT_WORLD_SEARCH",
|
"CONTEXT_WORLD_SEARCH",
|
||||||
"",
|
"",
|
||||||
"CONTEXT_WORLD_LIST",
|
"CONTEXT_WORLD_LIST",
|
||||||
"GAME_INVENTORY",
|
|
||||||
"",
|
"",
|
||||||
)
|
"GAME_INVENTORY",
|
||||||
|
)*/
|
||||||
private val buttonGapSize = 120
|
private val buttonGapSize = 120
|
||||||
private val highlighterYPos = icons.tileH + 4
|
private val highlighterYPos = icons.tileH + 4
|
||||||
|
|
||||||
var selection = 2
|
var selectedPanel = 2; private set
|
||||||
|
|
||||||
private val buttons = Array<UIItemImageButton>(5) {
|
/** (oldIndex: Int?, newIndex: Int) -> Unit
|
||||||
|
* Indices are raw index. That is, not re-arranged. */
|
||||||
|
var selectionChangeListener: ((Int?, Int) -> Unit)? = null
|
||||||
|
|
||||||
|
private var transitionFired = false
|
||||||
|
|
||||||
|
/*private val buttons = Array<UIItemImageButton>(5) {
|
||||||
val xoff = if (it == 1) -32 else if (it == 3) 32 else 0
|
val xoff = if (it == 1) -32 else if (it == 3) 32 else 0
|
||||||
UIItemImageButton(
|
UIItemImageButton(
|
||||||
parentUI,
|
parentUI,
|
||||||
@@ -207,17 +278,41 @@ class UIItemWorldPortalTopBar(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val workingButtons = arrayOf(0,2,4)*/
|
||||||
|
|
||||||
|
override fun update(delta: Float) {
|
||||||
|
super.update(delta)
|
||||||
|
|
||||||
|
|
||||||
|
/*workingButtons.forEach { buttons[it].update(delta) }
|
||||||
|
|
||||||
|
// transition stuffs
|
||||||
|
workingButtons.filter { buttons[it].mousePushed }.firstOrNull()?.let { pushedButton ->
|
||||||
|
if (selectedPanel != pushedButton) transitionFired = true
|
||||||
|
selectedPanel = pushedButton
|
||||||
|
|
||||||
|
workingButtons.forEach { i ->
|
||||||
|
buttons[i].highlighted = i == pushedButton
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if (transitionFired) {
|
||||||
|
transitionFired = false
|
||||||
|
panelTransitionReqFun(selectedPanel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun render(batch: SpriteBatch, camera: Camera) {
|
override fun render(batch: SpriteBatch, camera: Camera) {
|
||||||
super.render(batch, camera)
|
super.render(batch, camera)
|
||||||
|
|
||||||
// button
|
// button
|
||||||
buttons.forEach { it.render(batch, camera) }
|
/*buttons.forEach { it.render(batch, camera) }
|
||||||
|
|
||||||
// label
|
// label
|
||||||
batch.color = Color.WHITE
|
batch.color = Color.WHITE
|
||||||
val text = Lang[catIconLabels[selection]]
|
val text = Lang[catIconLabels[selectedPanel]]
|
||||||
App.fontGame.draw(batch, text, buttons[selection].posX + 10 - (App.fontGame.getWidth(text) / 2), posY + highlighterYPos + 4)
|
App.fontGame.draw(batch, text, buttons[selectedPanel].posX + 10 - (App.fontGame.getWidth(text) / 2), posY + highlighterYPos + 4)
|
||||||
|
*/
|
||||||
|
|
||||||
blendNormalStraightAlpha(batch)
|
blendNormalStraightAlpha(batch)
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,252 @@
|
|||||||
package net.torvald.terrarum.modulebasegame.ui
|
package net.torvald.terrarum.modulebasegame.ui
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Camera
|
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.SpriteBatch
|
||||||
import net.torvald.terrarum.App
|
import net.torvald.terrarum.*
|
||||||
|
import net.torvald.terrarum.gameactors.AVKey
|
||||||
|
import net.torvald.terrarum.gameitems.GameItem
|
||||||
|
import net.torvald.terrarum.langpack.Lang
|
||||||
|
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory
|
||||||
import net.torvald.terrarum.ui.Toolkit
|
import net.torvald.terrarum.ui.Toolkit
|
||||||
import net.torvald.terrarum.ui.UICanvas
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
|
import net.torvald.unicode.getKeycapPC
|
||||||
|
|
||||||
class UIWorldPortalCargo(val full: UIWorldPortal) : UICanvas() {
|
class UIWorldPortalCargo(val full: UIWorldPortal) : UICanvas(), HasInventory {
|
||||||
|
|
||||||
override var width: Int = Toolkit.drawWidth
|
override var width: Int = Toolkit.drawWidth
|
||||||
override var height: Int = App.scr.height
|
override var height: Int = App.scr.height
|
||||||
|
|
||||||
override fun updateUI(delta: Float) {
|
lateinit var chestInventory: FixtureInventory
|
||||||
TODO("Not yet implemented")
|
lateinit var chestNameFun: () -> String
|
||||||
|
|
||||||
|
private val negotiator = object : InventoryTransactionNegotiator() {
|
||||||
|
override fun accept(player: FixtureInventory, fixture: FixtureInventory, item: GameItem, amount: Long) {
|
||||||
|
player.remove(item, amount)
|
||||||
|
fixture.add(item, amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reject(fixture: FixtureInventory, player: FixtureInventory, item: GameItem, amount: Long) {
|
||||||
|
fixture.remove(item, amount)
|
||||||
|
player.add(item, amount)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getNegotiator() = negotiator
|
||||||
|
override fun getFixtureInventory(): FixtureInventory = chestInventory
|
||||||
|
override fun getPlayerInventory(): FixtureInventory = INGAME.actorNowPlaying!!.inventory
|
||||||
|
|
||||||
|
private val catBar: UIItemInventoryCatBar
|
||||||
|
private val itemListChest: UIItemInventoryItemGrid
|
||||||
|
private val itemListPlayer: UIItemInventoryItemGrid
|
||||||
|
|
||||||
|
private var encumbrancePerc = 0f
|
||||||
|
private var isEncumbered = false
|
||||||
|
|
||||||
|
private var halfSlotOffset = (UIItemInventoryElemSimple.height + UIItemInventoryItemGrid.listGap * 2) / 2
|
||||||
|
|
||||||
|
init {
|
||||||
|
catBar = UIItemInventoryCatBar(
|
||||||
|
this,
|
||||||
|
(width - UIInventoryFull.catBarWidth) / 2,
|
||||||
|
42 - UIInventoryFull.YPOS_CORRECTION + (App.scr.height - UIInventoryFull.internalHeight) / 2,
|
||||||
|
UIInventoryFull.internalWidth,
|
||||||
|
UIInventoryFull.catBarWidth,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
catBar.selectionChangeListener = { old, new -> itemListUpdate() }
|
||||||
|
itemListChest = UIItemInventoryItemGrid(
|
||||||
|
this,
|
||||||
|
catBar,
|
||||||
|
{ getFixtureInventory() },
|
||||||
|
Toolkit.hdrawWidth - UIInventoryFull.getWidthOfCells(6) - halfSlotOffset,
|
||||||
|
UIInventoryFull.INVENTORY_CELLS_OFFSET_Y(),
|
||||||
|
6, UIInventoryFull.CELLS_VRT,
|
||||||
|
drawScrollOnRightside = false,
|
||||||
|
drawWallet = false,
|
||||||
|
keyDownFun = { _, _, _, _, _ -> Unit },
|
||||||
|
touchDownFun = { gameItem, amount, button, _, _ ->
|
||||||
|
if (button == App.getConfigInt("config_mouseprimary")) {
|
||||||
|
if (gameItem != null) {
|
||||||
|
negotiator.reject(getFixtureInventory(), getPlayerInventory(), gameItem, amount)
|
||||||
|
}
|
||||||
|
itemListUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
// make grid mode buttons work together
|
||||||
|
itemListChest.navRemoCon.listButtonListener = { _,_ -> setCompact(false) }
|
||||||
|
itemListChest.navRemoCon.gridButtonListener = { _,_ -> setCompact(true) }
|
||||||
|
|
||||||
|
itemListPlayer = UIItemInventoryItemGrid(
|
||||||
|
this,
|
||||||
|
catBar,
|
||||||
|
{ INGAME.actorNowPlaying!!.inventory }, // literally a player's inventory
|
||||||
|
Toolkit.hdrawWidth + halfSlotOffset,
|
||||||
|
UIInventoryFull.INVENTORY_CELLS_OFFSET_Y(),
|
||||||
|
6, UIInventoryFull.CELLS_VRT,
|
||||||
|
drawScrollOnRightside = true,
|
||||||
|
drawWallet = false,
|
||||||
|
keyDownFun = { _, _, _, _, _ -> Unit },
|
||||||
|
touchDownFun = { gameItem, amount, button, _, _ ->
|
||||||
|
if (button == App.getConfigInt("config_mouseprimary")) {
|
||||||
|
if (gameItem != null) {
|
||||||
|
negotiator.accept(getPlayerInventory(), getFixtureInventory(), gameItem, amount)
|
||||||
|
}
|
||||||
|
itemListUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
itemListPlayer.navRemoCon.listButtonListener = { _,_ -> setCompact(false) }
|
||||||
|
itemListPlayer.navRemoCon.gridButtonListener = { _,_ -> setCompact(true) }
|
||||||
|
|
||||||
|
handler.allowESCtoClose = true
|
||||||
|
|
||||||
|
addUIitem(itemListChest)
|
||||||
|
addUIitem(itemListPlayer)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var openingClickLatched = false
|
||||||
|
|
||||||
|
override fun show() {
|
||||||
|
itemListPlayer.getInventory = { INGAME.actorNowPlaying!!.inventory }
|
||||||
|
|
||||||
|
itemListUpdate()
|
||||||
|
|
||||||
|
openingClickLatched = Terrarum.mouseDown
|
||||||
|
|
||||||
|
UIItemInventoryItemGrid.tooltipShowing.clear()
|
||||||
|
INGAME.setTooltipMessage(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun itemListUpdate() {
|
||||||
|
itemListChest.rebuild(catBar.catIconsMeaning[catBar.selectedIcon])
|
||||||
|
itemListPlayer.rebuild(catBar.catIconsMeaning[catBar.selectedIcon])
|
||||||
|
|
||||||
|
encumbrancePerc = getPlayerInventory().capacity.toFloat() / getPlayerInventory().maxCapacity
|
||||||
|
isEncumbered = getPlayerInventory().isEncumbered
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setCompact(yes: Boolean) {
|
||||||
|
itemListChest.isCompactMode = yes
|
||||||
|
itemListChest.navRemoCon.gridModeButtons[0].highlighted = !yes
|
||||||
|
itemListChest.navRemoCon.gridModeButtons[1].highlighted = yes
|
||||||
|
itemListChest.itemPage = 0
|
||||||
|
itemListChest.rebuild(catBar.catIconsMeaning[catBar.selectedIcon])
|
||||||
|
|
||||||
|
itemListPlayer.isCompactMode = yes
|
||||||
|
itemListPlayer.navRemoCon.gridModeButtons[0].highlighted = !yes
|
||||||
|
itemListPlayer.navRemoCon.gridModeButtons[1].highlighted = yes
|
||||||
|
itemListPlayer.itemPage = 0
|
||||||
|
itemListPlayer.rebuild(catBar.catIconsMeaning[catBar.selectedIcon])
|
||||||
|
|
||||||
|
itemListUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||||
|
if (!openingClickLatched) {
|
||||||
|
return super.touchDown(screenX, screenY, pointer, button)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateUI(delta: Float) {
|
||||||
|
catBar.update(delta)
|
||||||
|
itemListChest.update(delta)
|
||||||
|
itemListPlayer.update(delta)
|
||||||
|
|
||||||
|
if (openingClickLatched && !Terrarum.mouseDown) openingClickLatched = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private val thisOffsetX = Toolkit.hdrawWidth - UIInventoryFull.getWidthOfCells(6) - halfSlotOffset
|
||||||
|
private val thisOffsetX2 = thisOffsetX + (UIItemInventoryItemGrid.listGap + UIItemInventoryElemWide.height) * 7
|
||||||
|
private val thisOffsetY = UIInventoryFull.INVENTORY_CELLS_OFFSET_Y()
|
||||||
|
private val cellsWidth = (UIItemInventoryItemGrid.listGap + UIItemInventoryElemWide.height) * 6 - UIItemInventoryItemGrid.listGap
|
||||||
|
|
||||||
|
private val controlHelp: String
|
||||||
|
get() = if (App.environment == RunningEnvironment.PC)
|
||||||
|
"${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||||
|
else
|
||||||
|
"${App.gamepadLabelStart} ${Lang["GAME_ACTION_CLOSE"]} "
|
||||||
|
|
||||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||||
TODO("Not yet implemented")
|
// background fill
|
||||||
|
UIInventoryFull.drawBackground(batch, 1f)
|
||||||
|
|
||||||
|
// UI items
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
|
||||||
|
catBar.render(batch, camera)
|
||||||
|
itemListChest.render(batch, camera)
|
||||||
|
itemListPlayer.render(batch, camera)
|
||||||
|
|
||||||
|
|
||||||
|
blendNormalStraightAlpha(batch)
|
||||||
|
|
||||||
|
// encumbrance meter
|
||||||
|
val encumbranceText = Lang["GAME_INVENTORY_ENCUMBRANCE"]
|
||||||
|
val chestName = chestNameFun()
|
||||||
|
val playerName = INGAME.actorNowPlaying!!.actorValue.getAsString(AVKey.NAME).orEmpty().let { it.ifBlank { Lang["GAME_INVENTORY"] } }
|
||||||
|
val encumbBarXPos = itemListPlayer.posX + itemListPlayer.width - UIInventoryCells.weightBarWidth + 36
|
||||||
|
val encumbBarTextXPos = encumbBarXPos - 6 - App.fontGame.getWidth(encumbranceText)
|
||||||
|
val yEnd = -UIInventoryFull.YPOS_CORRECTION + (App.scr.height + UIInventoryFull.internalHeight).div(2).toFloat() // directly copied from UIInventoryFull.yEnd
|
||||||
|
val encumbBarYPos = yEnd - 20 + 3 // dunno why but extra 3 px is needed
|
||||||
|
val encumbCol = UIItemInventoryCellCommonRes.getHealthMeterColour(1f - encumbrancePerc, 0f, 1f)
|
||||||
|
val encumbBack = encumbCol mul UIItemInventoryCellCommonRes.meterBackDarkening
|
||||||
|
|
||||||
|
// encumbrance bar background
|
||||||
|
batch.color = encumbBack
|
||||||
|
Toolkit.fillArea(
|
||||||
|
batch,
|
||||||
|
encumbBarXPos,
|
||||||
|
encumbBarYPos,
|
||||||
|
UIInventoryCells.weightBarWidth,
|
||||||
|
UIInventoryFull.controlHelpHeight - 6f
|
||||||
|
)
|
||||||
|
// encumbrance bar
|
||||||
|
batch.color = encumbCol
|
||||||
|
Toolkit.fillArea(
|
||||||
|
batch,
|
||||||
|
encumbBarXPos, encumbBarYPos,
|
||||||
|
if (getPlayerInventory().capacityMode == FixtureInventory.CAPACITY_MODE_NO_ENCUMBER)
|
||||||
|
1f
|
||||||
|
else // make sure 1px is always be seen
|
||||||
|
minOf(UIInventoryCells.weightBarWidth, maxOf(1f, UIInventoryCells.weightBarWidth * encumbrancePerc)),
|
||||||
|
UIInventoryFull.controlHelpHeight - 6f
|
||||||
|
)
|
||||||
|
|
||||||
|
// chest name text
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
App.fontGame.draw(batch, chestName, thisOffsetX + (cellsWidth - App.fontGame.getWidth(chestName)) / 2, thisOffsetY - 30)
|
||||||
|
App.fontGame.draw(batch, playerName, thisOffsetX2 + (cellsWidth - App.fontGame.getWidth(playerName)) / 2, thisOffsetY - 30)
|
||||||
|
|
||||||
|
// control hint
|
||||||
|
App.fontGame.draw(batch, controlHelp, thisOffsetX - 34f, encumbBarYPos - 3)
|
||||||
|
|
||||||
|
// encumb text
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
App.fontGame.draw(batch, encumbranceText, encumbBarTextXPos, encumbBarYPos - 3f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun doOpening(delta: Float) {
|
||||||
|
INGAME.pause()
|
||||||
|
INGAME.setTooltipMessage(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doClosing(delta: Float) {
|
||||||
|
INGAME.resume()
|
||||||
|
INGAME.setTooltipMessage(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun endOpening(delta: Float) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun endClosing(delta: Float) {
|
||||||
|
UIItemInventoryItemGrid.tooltipShowing.clear()
|
||||||
|
INGAME.setTooltipMessage(null) // required!
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,11 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
|||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
|
import net.torvald.terrarum.App.printdbg
|
||||||
import net.torvald.terrarum.gameactors.AVKey
|
import net.torvald.terrarum.gameactors.AVKey
|
||||||
|
import net.torvald.terrarum.gameworld.fmod
|
||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
|
import net.torvald.terrarum.modulebasegame.gameactors.FixtureWorldPortal
|
||||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVENTORY_CELLS_OFFSET_Y
|
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVENTORY_CELLS_OFFSET_Y
|
||||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.getCellCountVertically
|
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.getCellCountVertically
|
||||||
import net.torvald.terrarum.realestate.LandUtil.CHUNK_H
|
import net.torvald.terrarum.realestate.LandUtil.CHUNK_H
|
||||||
@@ -28,8 +31,16 @@ import java.time.Instant
|
|||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.zip.GZIPInputStream
|
import java.util.zip.GZIPInputStream
|
||||||
|
import kotlin.math.ceil
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
|
* "Teleport" button sets the destination and makes the portal surface to 'glow' to indicate the teleportation is ready.
|
||||||
|
* Teleportation is initiated with a rising edge of a logic signal.
|
||||||
|
*
|
||||||
|
* "New World" sets the parameter of the new world, and make the new (not yet generated) world as the teleportation target.
|
||||||
|
* THe world generation will be done when the "teleportation" is on going.
|
||||||
|
*
|
||||||
* Created by minjaesong on 2023-05-19.
|
* Created by minjaesong on 2023-05-19.
|
||||||
*/
|
*/
|
||||||
class UIWorldPortalListing(val full: UIWorldPortal) : UICanvas() {
|
class UIWorldPortalListing(val full: UIWorldPortal) : UICanvas() {
|
||||||
@@ -47,31 +58,67 @@ class UIWorldPortalListing(val full: UIWorldPortal) : UICanvas() {
|
|||||||
private val textAreaW = thumbw - 32
|
private val textAreaW = thumbw - 32
|
||||||
private val thumbh = 252
|
private val thumbh = 252
|
||||||
private val hx = Toolkit.drawWidth.div(2)
|
private val hx = Toolkit.drawWidth.div(2)
|
||||||
private val y = INVENTORY_CELLS_OFFSET_Y() + 1
|
private val y = INVENTORY_CELLS_OFFSET_Y() + 1 - 34
|
||||||
|
|
||||||
private val listCount = getCellCountVertically(UIItemWorldCellsSimple.height, gridGap)
|
private val listCount = getCellCountVertically(UIItemWorldCellsSimple.height, gridGap)
|
||||||
private val listHeight = UIItemWorldCellsSimple.height + (listCount - 1) * (UIItemWorldCellsSimple.height + gridGap)
|
private val listHeight = UIItemWorldCellsSimple.height + (listCount - 1) * (UIItemWorldCellsSimple.height + gridGap)
|
||||||
|
|
||||||
private val memoryGaugeWidth = textAreaW
|
private val memoryGaugeWidth = textAreaW
|
||||||
private val deleteButtonWidth = (thumbw - gridGap) / 2
|
private val deleteButtonWidth = (thumbw - gridGap) / 2
|
||||||
private val buttonDeleteWorld = UIItemTextButton(this,
|
private val buttonsY = y + listHeight + gridGap
|
||||||
"MENU_LABEL_DELETE",
|
|
||||||
|
private val buttonSearch = UIItemTextButton(this,
|
||||||
|
"CONTEXT_WORLD_NEW",
|
||||||
|
hx - gridGap/2 - 2*deleteButtonWidth - gridGap,
|
||||||
|
buttonsY,
|
||||||
|
deleteButtonWidth,
|
||||||
|
readFromLang = true,
|
||||||
|
hasBorder = true,
|
||||||
|
alignment = UIItemTextButton.Companion.Alignment.CENTRE
|
||||||
|
).also {
|
||||||
|
it.clickOnceListener = { _,_ ->
|
||||||
|
full.requestTransition(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private val buttonTeleport = UIItemTextButton(this,
|
||||||
|
"GAME_ACTION_TELEPORT",
|
||||||
hx - gridGap/2 - deleteButtonWidth,
|
hx - gridGap/2 - deleteButtonWidth,
|
||||||
y + listHeight - buttonHeight,
|
buttonsY,
|
||||||
deleteButtonWidth,
|
deleteButtonWidth,
|
||||||
readFromLang = true,
|
readFromLang = true,
|
||||||
hasBorder = true,
|
hasBorder = true,
|
||||||
alignment = UIItemTextButton.Companion.Alignment.CENTRE
|
alignment = UIItemTextButton.Companion.Alignment.CENTRE
|
||||||
)
|
).also {
|
||||||
private val buttonRenameWorld = UIItemTextButton(this,
|
it.clickOnceListener = { _,_ ->
|
||||||
|
if (selected?.worldInfo != null) {
|
||||||
|
full.host.teleportRequest = FixtureWorldPortal.TeleportRequest(
|
||||||
|
selected?.worldInfo?.diskSkimmer, null
|
||||||
|
)
|
||||||
|
full.setAsClose()
|
||||||
|
printdbg(this, "Teleport target set: ${full.host.teleportRequest}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private val buttonRename = UIItemTextButton(this,
|
||||||
"MENU_LABEL_RENAME",
|
"MENU_LABEL_RENAME",
|
||||||
buttonDeleteWorld.posX - gridGap - deleteButtonWidth,
|
hx + gridGap/2,
|
||||||
y + listHeight - buttonHeight,
|
buttonsY,
|
||||||
deleteButtonWidth,
|
deleteButtonWidth,
|
||||||
readFromLang = true,
|
readFromLang = true,
|
||||||
hasBorder = true,
|
hasBorder = true,
|
||||||
alignment = UIItemTextButton.Companion.Alignment.CENTRE
|
alignment = UIItemTextButton.Companion.Alignment.CENTRE
|
||||||
)
|
)
|
||||||
|
private val buttonDelete = UIItemTextButton(this,
|
||||||
|
"MENU_LABEL_DELETE",
|
||||||
|
hx + gridGap/2 + deleteButtonWidth + gridGap,
|
||||||
|
buttonsY,
|
||||||
|
deleteButtonWidth,
|
||||||
|
readFromLang = true,
|
||||||
|
hasBorder = true,
|
||||||
|
alignment = UIItemTextButton.Companion.Alignment.CENTRE
|
||||||
|
)
|
||||||
|
|
||||||
|
private val navRemoCon = UIItemListNavBarVertical(full, hx + 6 + UIItemWorldCellsSimple.width, y + 7, listHeight + 2, false)
|
||||||
|
|
||||||
private val worldList = ArrayList<WorldInfo>()
|
private val worldList = ArrayList<WorldInfo>()
|
||||||
data class WorldInfo(
|
data class WorldInfo(
|
||||||
@@ -88,32 +135,54 @@ class UIWorldPortalListing(val full: UIWorldPortal) : UICanvas() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun disableListEditButtons() {
|
||||||
|
buttonRename.isEnabled = false
|
||||||
|
buttonDelete.isEnabled = false
|
||||||
|
buttonTeleport.isEnabled = false
|
||||||
|
currentWorldSelected = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun highlightListEditButtons(info: WorldInfo?) {
|
||||||
|
// will disable the delete and teleport button if the world is equal to the currently playing world
|
||||||
|
|
||||||
|
if (info == null) disableListEditButtons()
|
||||||
|
else {
|
||||||
|
buttonRename.isEnabled = true
|
||||||
|
buttonDelete.isEnabled = info.uuid != INGAME.world.worldIndex
|
||||||
|
buttonTeleport.isEnabled = info.uuid != INGAME.world.worldIndex
|
||||||
|
currentWorldSelected = info.uuid == INGAME.world.worldIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var currentWorldSelected = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
CommonResourcePool.addToLoadingList("terrarum-basegame-worldportalicons") {
|
CommonResourcePool.addToLoadingList("terrarum-basegame-worldportalicons") {
|
||||||
TextureRegionPack(ModMgr.getGdxFile("basegame", "gui/worldportal_catbar.tga"), 30, 20)
|
TextureRegionPack(ModMgr.getGdxFile("basegame", "gui/worldportal_catbar.tga"), 30, 20)
|
||||||
}
|
}
|
||||||
CommonResourcePool.loadAll()
|
CommonResourcePool.loadAll()
|
||||||
|
|
||||||
|
navRemoCon.scrollUpListener = { _,_ -> scrollItemPage(-1) }
|
||||||
|
navRemoCon.scrollDownListener = { _,_ -> scrollItemPage(1) }
|
||||||
|
|
||||||
addUIitem(buttonRenameWorld)
|
addUIitem(buttonDelete)
|
||||||
addUIitem(buttonDeleteWorld)
|
addUIitem(buttonRename)
|
||||||
|
addUIitem(buttonTeleport)
|
||||||
|
addUIitem(buttonSearch)
|
||||||
|
addUIitem(navRemoCon)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var chunksUsed = 0
|
fun scrollItemPage(relativeAmount: Int) {
|
||||||
private val chunksMax = 100000
|
listPage = if (listPageCount == 0) 0 else (listPage + relativeAmount).fmod(listPageCount)
|
||||||
|
}
|
||||||
|
|
||||||
private lateinit var worldCells: Array<UIItemWorldCellsSimple>
|
private fun readWorldList() {
|
||||||
|
|
||||||
private var selected: UIItemWorldCellsSimple? = null
|
|
||||||
private var selectedIndex: Int? = null
|
|
||||||
|
|
||||||
override fun show() {
|
|
||||||
worldList.clear()
|
worldList.clear()
|
||||||
(INGAME.actorGamer.actorValue.getAsString(AVKey.WORLD_PORTAL_DICT) ?: "").split(",").filter { it.isNotBlank() }.map {
|
(INGAME.actorGamer.actorValue.getAsString(AVKey.WORLD_PORTAL_DICT) ?: "").split(",").filter { it.isNotBlank() }.map {
|
||||||
it.ascii85toUUID().let { it to App.savegameWorlds[it] }
|
it.ascii85toUUID().let { it to App.savegameWorlds[it] }
|
||||||
}.filter { it.second != null }.mapIndexed { index, (uuid, disk) ->
|
}.filter { it.second != null }.mapIndexed { index, (uuid, disk0) ->
|
||||||
|
|
||||||
|
val disk = disk0!!.loadable()
|
||||||
var chunksCount = 0
|
var chunksCount = 0
|
||||||
var seed = 0L
|
var seed = 0L
|
||||||
var lastPlayed = 0L
|
var lastPlayed = 0L
|
||||||
@@ -122,6 +191,8 @@ class UIWorldPortalListing(val full: UIWorldPortal) : UICanvas() {
|
|||||||
var h = 0
|
var h = 0
|
||||||
var thumb: TextureRegion? = null
|
var thumb: TextureRegion? = null
|
||||||
|
|
||||||
|
disk.rebuild()
|
||||||
|
|
||||||
JsonFetcher.readFromJsonString(ByteArray64Reader(disk!!.requestFile(-1)!!.contents.getContent() as ByteArray64, Common.CHARSET)).let {
|
JsonFetcher.readFromJsonString(ByteArray64Reader(disk!!.requestFile(-1)!!.contents.getContent() as ByteArray64, Common.CHARSET)).let {
|
||||||
JsonFetcher.forEachSiblings(it) { name, value ->
|
JsonFetcher.forEachSiblings(it) { name, value ->
|
||||||
if (name == "width") w = value.asInt()
|
if (name == "width") w = value.asInt()
|
||||||
@@ -148,31 +219,63 @@ class UIWorldPortalListing(val full: UIWorldPortal) : UICanvas() {
|
|||||||
}.let {
|
}.let {
|
||||||
worldList.addAll(it)
|
worldList.addAll(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
chunksUsed = worldList.sumOf { it.dimensionInChunks }
|
chunksUsed = worldList.sumOf { it.dimensionInChunks }
|
||||||
|
listPageCount = ceil(worldList.size.toDouble() / listCount).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
worldCells = Array(maxOf(worldList.size, listCount)) {
|
private var chunksUsed = 0
|
||||||
|
private val chunksMax = 100000
|
||||||
|
|
||||||
|
private lateinit var worldCells: Array<UIItemWorldCellsSimple>
|
||||||
|
|
||||||
|
private var selected: UIItemWorldCellsSimple? = null
|
||||||
|
private var selectedIndex: Int? = null
|
||||||
|
|
||||||
|
var listPage
|
||||||
|
set(value) {
|
||||||
|
navRemoCon.itemPage = if (listPageCount == 0) 0 else (value).fmod(listPageCount)
|
||||||
|
rebuildList()
|
||||||
|
}
|
||||||
|
get() = navRemoCon.itemPage
|
||||||
|
|
||||||
|
var listPageCount // TODO total size of current category / items.size
|
||||||
|
protected set(value) {
|
||||||
|
navRemoCon.itemPageCount = value
|
||||||
|
}
|
||||||
|
get() = navRemoCon.itemPageCount
|
||||||
|
|
||||||
|
private fun rebuildList() {
|
||||||
|
worldCells = Array(listCount) { it0 ->
|
||||||
|
val it = it0 + listCount * listPage
|
||||||
UIItemWorldCellsSimple(
|
UIItemWorldCellsSimple(
|
||||||
this,
|
this,
|
||||||
hx + gridGap / 2,
|
hx + gridGap / 2,
|
||||||
y + (gridGap + UIItemWorldCellsSimple.height) * it,
|
y + (gridGap + UIItemWorldCellsSimple.height) * it0,
|
||||||
worldList.getOrNull(it),
|
worldList.getOrNull(it),
|
||||||
worldList.getOrNull(it)?.diskSkimmer?.getDiskName(Common.CHARSET)
|
worldList.getOrNull(it)?.diskSkimmer?.getDiskName(Common.CHARSET)
|
||||||
).also { button ->
|
).also { button ->
|
||||||
button.clickOnceListener = { _, _, _ ->
|
button.clickOnceListener = { _, _ ->
|
||||||
selected = button
|
selected = button
|
||||||
selectedIndex = it
|
selectedIndex = it
|
||||||
|
highlightListEditButtons(worldList.getOrNull(it))
|
||||||
updateUIbyButtonSelection()
|
updateUIbyButtonSelection()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun show() {
|
||||||
|
listPage = 0
|
||||||
|
|
||||||
|
readWorldList()
|
||||||
|
|
||||||
|
rebuildList()
|
||||||
|
|
||||||
uiItems.forEach { it.show() }
|
uiItems.forEach { it.show() }
|
||||||
worldCells.forEach { it.show() }
|
worldCells.forEach { it.show() }
|
||||||
selected = null
|
selected = null
|
||||||
|
|
||||||
|
disableListEditButtons()
|
||||||
updateUIbyButtonSelection()
|
updateUIbyButtonSelection()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +303,11 @@ class UIWorldPortalListing(val full: UIWorldPortal) : UICanvas() {
|
|||||||
|
|
||||||
override fun updateUI(delta: Float) {
|
override fun updateUI(delta: Float) {
|
||||||
uiItems.forEach { it.update(delta) }
|
uiItems.forEach { it.update(delta) }
|
||||||
worldCells.forEach { it.update(delta) }
|
if (::worldCells.isInitialized) worldCells.forEach { it.update(delta) }
|
||||||
|
|
||||||
|
if (currentWorldSelected) {
|
||||||
|
INGAME.setTooltipMessage(if (buttonTeleport.mouseUp || buttonDelete.mouseUp) Lang["CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING"] else null)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val iconGap = 12f
|
private val iconGap = 12f
|
||||||
@@ -231,7 +338,7 @@ class UIWorldPortalListing(val full: UIWorldPortal) : UICanvas() {
|
|||||||
val icons = CommonResourcePool.getAsTextureRegionPack("terrarum-basegame-worldportalicons")
|
val icons = CommonResourcePool.getAsTextureRegionPack("terrarum-basegame-worldportalicons")
|
||||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||||
val memoryGaugeXpos = hx - memoryGaugeWidth - gridGap/2
|
val memoryGaugeXpos = hx - memoryGaugeWidth - gridGap/2
|
||||||
val memoryGaugeYpos = y + listHeight - buttonHeight - gridGap - buttonHeight
|
val memoryGaugeYpos = y + listHeight - buttonHeight
|
||||||
val textXpos = memoryGaugeXpos + 3
|
val textXpos = memoryGaugeXpos + 3
|
||||||
|
|
||||||
// draw background //
|
// draw background //
|
||||||
@@ -291,7 +398,7 @@ class UIWorldPortalListing(val full: UIWorldPortal) : UICanvas() {
|
|||||||
|
|
||||||
|
|
||||||
uiItems.forEach { it.render(batch, camera) }
|
uiItems.forEach { it.render(batch, camera) }
|
||||||
worldCells.forEach { it.render(batch, camera) }
|
if (::worldCells.isInitialized) worldCells.forEach { it.render(batch, camera) }
|
||||||
|
|
||||||
// control hints
|
// control hints
|
||||||
batch.color = Color.WHITE
|
batch.color = Color.WHITE
|
||||||
@@ -300,15 +407,15 @@ class UIWorldPortalListing(val full: UIWorldPortal) : UICanvas() {
|
|||||||
|
|
||||||
override fun hide() {
|
override fun hide() {
|
||||||
uiItems.forEach { it.hide() }
|
uiItems.forEach { it.hide() }
|
||||||
worldCells.forEach { it.hide() }
|
if (::worldCells.isInitialized) worldCells.forEach { it.hide() }
|
||||||
|
|
||||||
worldCells.forEach { try { it.dispose() } catch (_: GdxRuntimeException) {} }
|
if (::worldCells.isInitialized) worldCells.forEach { try { it.dispose() } catch (_: GdxRuntimeException) {} }
|
||||||
worldList.forEach { try { it.dispose() } catch (_: GdxRuntimeException) {} }
|
worldList.forEach { try { it.dispose() } catch (_: GdxRuntimeException) {} }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
uiItems.forEach { it.dispose() }
|
uiItems.forEach { it.dispose() }
|
||||||
worldCells.forEach { try { it.dispose() } catch (_: GdxRuntimeException) {} }
|
if (::worldCells.isInitialized) worldCells.forEach { try { it.dispose() } catch (_: GdxRuntimeException) {} }
|
||||||
worldList.forEach { try { it.dispose() } catch (_: GdxRuntimeException) {} }
|
worldList.forEach { try { it.dispose() } catch (_: GdxRuntimeException) {} }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,17 +432,50 @@ class UIWorldPortalListing(val full: UIWorldPortal) : UICanvas() {
|
|||||||
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||||
if (this.isVisible) {
|
if (this.isVisible) {
|
||||||
uiItems.forEach { it.touchUp(screenX, screenY, pointer, button) }
|
uiItems.forEach { it.touchUp(screenX, screenY, pointer, button) }
|
||||||
worldCells.forEach { it.touchUp(screenX, screenY, pointer, button) }
|
if (::worldCells.isInitialized) worldCells.forEach { it.touchUp(screenX, screenY, pointer, button) }
|
||||||
handler.subUIs.forEach { it.touchUp(screenX, screenY, pointer, button) }
|
handler.subUIs.forEach { it.touchUp(screenX, screenY, pointer, button) }
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
else return false
|
else return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun scrolled(amountX: Float, amountY: Float): Boolean {
|
||||||
|
if (this.isVisible) {
|
||||||
|
uiItems.forEach { it.scrolled(amountX, amountY) }
|
||||||
|
if (::worldCells.isInitialized) worldCells.forEach { it.scrolled(amountX, amountY) }
|
||||||
|
handler.subUIs.forEach { it.scrolled(amountX, amountY) }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doOpening(delta: Float) {
|
||||||
|
super.doOpening(delta)
|
||||||
|
INGAME.pause()
|
||||||
|
INGAME.setTooltipMessage(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doClosing(delta: Float) {
|
||||||
|
super.doClosing(delta)
|
||||||
|
INGAME.resume()
|
||||||
|
INGAME.setTooltipMessage(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun endOpening(delta: Float) {
|
||||||
|
super.endOpening(delta)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun endClosing(delta: Float) {
|
||||||
|
super.endClosing(delta)
|
||||||
|
UIItemInventoryItemGrid.tooltipShowing.clear()
|
||||||
|
INGAME.setTooltipMessage(null) // required!
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class UIItemWorldCellsSimple(
|
class UIItemWorldCellsSimple(
|
||||||
parent: UIWorldPortalListing,
|
val parent: UIWorldPortalListing,
|
||||||
initialX: Int,
|
initialX: Int,
|
||||||
initialY: Int,
|
initialY: Int,
|
||||||
internal val worldInfo: UIWorldPortalListing.WorldInfo? = null,
|
internal val worldInfo: UIWorldPortalListing.WorldInfo? = null,
|
||||||
@@ -396,6 +536,15 @@ class UIItemWorldCellsSimple(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun scrolled(amountX: Float, amountY: Float): Boolean {
|
||||||
|
|
||||||
|
if (mouseUp) {
|
||||||
|
parent.scrollItemPage(amountY.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,28 +1,174 @@
|
|||||||
package net.torvald.terrarum.modulebasegame.ui
|
package net.torvald.terrarum.modulebasegame.ui
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Camera
|
import com.badlogic.gdx.graphics.Camera
|
||||||
|
import com.badlogic.gdx.graphics.Color
|
||||||
|
import com.badlogic.gdx.graphics.Texture
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||||
|
import net.torvald.random.HQRNG
|
||||||
|
import net.torvald.random.XXHash64
|
||||||
import net.torvald.terrarum.App
|
import net.torvald.terrarum.App
|
||||||
import net.torvald.terrarum.ui.Toolkit
|
import net.torvald.terrarum.ModMgr
|
||||||
import net.torvald.terrarum.ui.UICanvas
|
import net.torvald.terrarum.Terrarum
|
||||||
|
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
|
||||||
|
import net.torvald.terrarum.langpack.Lang
|
||||||
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
|
import net.torvald.terrarum.modulebasegame.WorldgenLoadScreen
|
||||||
|
import net.torvald.terrarum.modulebasegame.gameactors.FixtureWorldPortal
|
||||||
|
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||||
|
import net.torvald.terrarum.modulebasegame.serialise.ReadActor
|
||||||
|
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVENTORY_CELLS_OFFSET_Y
|
||||||
|
import net.torvald.terrarum.savegame.ByteArray64Reader
|
||||||
|
import net.torvald.terrarum.savegame.VDFileID
|
||||||
|
import net.torvald.terrarum.savegame.VirtualDisk
|
||||||
|
import net.torvald.terrarum.serialise.Common
|
||||||
|
import net.torvald.terrarum.ui.*
|
||||||
|
import net.torvald.terrarum.utils.RandomWordsName
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by minjaesong on 2023-05-19.
|
* Created by minjaesong on 2023-05-19.
|
||||||
*/
|
*/
|
||||||
class UIWorldPortalSearch(val full: UIWorldPortal) : UICanvas() {
|
class UIWorldPortalSearch(val full: UIWorldPortal) : UICanvas() {
|
||||||
|
|
||||||
override var width: Int = Toolkit.drawWidth
|
// override var width: Int = Toolkit.drawWidth
|
||||||
override var height: Int = App.scr.height
|
// override var height: Int = App.scr.height
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private val hugeTex = TextureRegion(Texture(ModMgr.getGdxFile("basegame", "gui/huge.png")))
|
||||||
|
private val largeTex = TextureRegion(Texture(ModMgr.getGdxFile("basegame", "gui/large.png")))
|
||||||
|
private val normalTex = TextureRegion(Texture(ModMgr.getGdxFile("basegame", "gui/normal.png")))
|
||||||
|
private val smallTex = TextureRegion(Texture(ModMgr.getGdxFile("basegame", "gui/small.png")))
|
||||||
|
|
||||||
|
private val tex = arrayOf(smallTex, normalTex, largeTex, hugeTex)
|
||||||
|
|
||||||
|
override var width = 480
|
||||||
|
override var height = 480
|
||||||
|
|
||||||
|
private val drawX = (Toolkit.drawWidth - width) / 2
|
||||||
|
private val drawY = (App.scr.height - height) / 2
|
||||||
|
|
||||||
|
private val radioCellWidth = 116
|
||||||
|
private val inputWidth = 340
|
||||||
|
private val radioX = (width - (radioCellWidth * tex.size + 9)) / 2
|
||||||
|
private val inputX = width - inputWidth
|
||||||
|
|
||||||
|
private val sizeSelY = 186 + 40
|
||||||
|
|
||||||
|
private val sizeSelector = UIItemInlineRadioButtons(this,
|
||||||
|
drawX + radioX, drawY + sizeSelY, radioCellWidth,
|
||||||
|
listOf(
|
||||||
|
{ Lang["CONTEXT_DESCRIPTION_TINY"] },
|
||||||
|
{ Lang["CONTEXT_DESCRIPTION_SMALL"] },
|
||||||
|
{ Lang["CONTEXT_DESCRIPTION_BIG"] },
|
||||||
|
{ Lang["CONTEXT_DESCRIPTION_HUGE"] }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val rng = HQRNG()
|
||||||
|
|
||||||
|
private val nameInput = UIItemTextLineInput(this,
|
||||||
|
drawX + width - inputWidth, drawY + sizeSelY + 80, inputWidth,
|
||||||
|
{ RandomWordsName(4) }, InputLenCap(VirtualDisk.NAME_LENGTH, InputLenCap.CharLenUnit.UTF8_BYTES)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val seedInput = UIItemTextLineInput(this,
|
||||||
|
drawX + width - inputWidth, drawY + sizeSelY + 120, inputWidth,
|
||||||
|
{ rng.nextLong().toString() }, InputLenCap(256, InputLenCap.CharLenUnit.CODEPOINTS)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val goButtonWidth = 180
|
||||||
|
private val backButton = UIItemTextButton(this, "MENU_LABEL_BACK", drawX + (width/2 - goButtonWidth) / 2, drawY + height - 24, goButtonWidth, true, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
|
||||||
|
private val goButton = UIItemTextButton(this, "MENU_LABEL_CONFIRM_BUTTON", drawX + width/2 + (width/2 - goButtonWidth) / 2, drawY + height - 24, goButtonWidth, true, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
|
||||||
|
|
||||||
|
init {
|
||||||
|
goButton.clickOnceListener = { _, _ ->
|
||||||
|
val seed = try {
|
||||||
|
seedInput.getTextOrPlaceholder().toLong()
|
||||||
|
}
|
||||||
|
catch (e: NumberFormatException) {
|
||||||
|
XXHash64.hash(seedInput.getTextOrPlaceholder().toByteArray(Charsets.UTF_8), 10000)
|
||||||
|
}
|
||||||
|
val (wx, wy) = TerrarumIngame.WORLDPORTAL_NEW_WORLD_SIZE[sizeSelector.selection]
|
||||||
|
val worldParam = TerrarumIngame.NewWorldParameters(wx, wy, seed, nameInput.getTextOrPlaceholder())
|
||||||
|
full.host.teleportRequest = FixtureWorldPortal.TeleportRequest(null, worldParam)
|
||||||
|
full.setAsClose()
|
||||||
|
}
|
||||||
|
backButton.clickOnceListener = { _, _ ->
|
||||||
|
full.requestTransition(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
addUIitem(sizeSelector)
|
||||||
|
addUIitem(seedInput) // order is important
|
||||||
|
addUIitem(nameInput) // because of the IME candidates overlay
|
||||||
|
addUIitem(goButton)
|
||||||
|
addUIitem(backButton)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun show() {
|
||||||
|
uiItems.forEach { it.show() }
|
||||||
|
seedInput.clearText()
|
||||||
|
seedInput.refreshPlaceholder()
|
||||||
|
nameInput.clearText()
|
||||||
|
nameInput.refreshPlaceholder()
|
||||||
|
}
|
||||||
|
|
||||||
|
private var oldPosX = full.posX
|
||||||
|
|
||||||
override fun updateUI(delta: Float) {
|
override fun updateUI(delta: Float) {
|
||||||
TODO("Not yet implemented")
|
uiItems.forEach { it.update(delta) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||||
TODO("Not yet implemented")
|
val posXDelta = posX - oldPosX
|
||||||
|
|
||||||
|
// ugh why won't you just scroll along??
|
||||||
|
seedInput.posX += posXDelta
|
||||||
|
nameInput.posX += posXDelta
|
||||||
|
goButton.posX += posXDelta
|
||||||
|
backButton.posX += posXDelta
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
// ui title
|
||||||
|
val titlestr = Lang["CONTEXT_WORLD_NEW"]
|
||||||
|
App.fontUITitle.draw(batch, titlestr, drawX + (width - App.fontUITitle.getWidth(titlestr)).div(2).toFloat(), INVENTORY_CELLS_OFFSET_Y() - 72f)
|
||||||
|
|
||||||
|
// draw size previews
|
||||||
|
val texture = tex[sizeSelector.selection.coerceAtMost(tex.lastIndex)]
|
||||||
|
val tx = drawX + (width - texture.regionWidth) / 2
|
||||||
|
val ty = drawY + (160 - texture.regionHeight) / 2
|
||||||
|
batch.draw(texture, tx.toFloat(), ty.toFloat())
|
||||||
|
// border
|
||||||
|
batch.color = Toolkit.Theme.COL_INACTIVE
|
||||||
|
Toolkit.drawBoxBorder(batch, tx - 1, ty - 1, texture.regionWidth + 2, texture.regionHeight + 2)
|
||||||
|
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
// size selector title
|
||||||
|
val sizestr = Lang["MENU_OPTIONS_SIZE"]
|
||||||
|
App.fontGame.draw(batch, sizestr, drawX + (width - App.fontGame.getWidth(sizestr)).div(2).toFloat(), drawY + sizeSelY - 40f)
|
||||||
|
|
||||||
|
// name/seed input labels
|
||||||
|
App.fontGame.draw(batch, Lang["MENU_NAME"], drawX, drawY + sizeSelY + 80)
|
||||||
|
App.fontGame.draw(batch, Lang["CONTEXT_GENERATOR_SEED"], drawX, drawY + sizeSelY + 120)
|
||||||
|
|
||||||
|
uiItems.forEach { it.render(batch, camera) }
|
||||||
|
|
||||||
|
|
||||||
|
oldPosX = posX
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hide() {
|
||||||
|
uiItems.forEach { it.hide() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
TODO("Not yet implemented")
|
hugeTex.texture.dispose()
|
||||||
|
largeTex.texture.dispose()
|
||||||
|
normalTex.texture.dispose()
|
||||||
|
smallTex.texture.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -50,13 +50,13 @@ removefile:
|
|||||||
|
|
||||||
fun checkFileSanity() {
|
fun checkFileSanity() {
|
||||||
if (!diskFile.exists()) throw NoSuchFileException(diskFile.absoluteFile)
|
if (!diskFile.exists()) throw NoSuchFileException(diskFile.absoluteFile)
|
||||||
if (diskFile.length() < 310L) throw RuntimeException("Invalid Virtual Disk file!")
|
if (diskFile.length() < 310L) throw RuntimeException("Invalid Virtual Disk file: ${diskFile.path}")
|
||||||
|
|
||||||
// check magic
|
// check magic
|
||||||
val fis = FileInputStream(diskFile)
|
val fis = FileInputStream(diskFile)
|
||||||
|
|
||||||
val magic = ByteArray(4).let { fis.read(it); it }
|
val magic = ByteArray(4).let { fis.read(it); it }
|
||||||
if (!magic.contentEquals(VirtualDisk.MAGIC)) throw RuntimeException("Invalid Virtual Disk file!")
|
if (!magic.contentEquals(VirtualDisk.MAGIC)) throw RuntimeException("Invalid Virtual Disk file: ${diskFile.path}")
|
||||||
|
|
||||||
fis.close()
|
fis.close()
|
||||||
}
|
}
|
||||||
@@ -221,7 +221,7 @@ removefile:
|
|||||||
fa.read(4).toIntBig().toLong()
|
fa.read(4).toIntBig().toLong()
|
||||||
}
|
}
|
||||||
DiskEntry.SYMLINK -> 8L
|
DiskEntry.SYMLINK -> 8L
|
||||||
else -> throw UnsupportedOperationException("Unsupported entry type: $fileFlag") // FIXME no support for compressed file
|
else -> throw UnsupportedOperationException("Unsupported entry type: $fileFlag for entryID $entryID at offset $offset") // FIXME no support for compressed file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -251,7 +251,7 @@ removefile:
|
|||||||
|
|
||||||
EntrySymlink(target)
|
EntrySymlink(target)
|
||||||
}
|
}
|
||||||
else -> throw UnsupportedOperationException("Unsupported entry type: $fileFlag") // FIXME no support for compressed file
|
else -> throw UnsupportedOperationException("Unsupported entry type: $fileFlag for entryID $entryID at offset $offset") // FIXME no support for compressed file
|
||||||
}
|
}
|
||||||
|
|
||||||
return DiskEntry(entryID, parent, creationTime, modifyTime, entryContent)
|
return DiskEntry(entryID, parent, creationTime, modifyTime, entryContent)
|
||||||
|
|||||||
@@ -503,8 +503,8 @@ object VDUtil {
|
|||||||
* Throws an exception if specified size cannot fit into the disk
|
* Throws an exception if specified size cannot fit into the disk
|
||||||
*/
|
*/
|
||||||
fun VirtualDisk.checkCapacity(newSize: Long) {
|
fun VirtualDisk.checkCapacity(newSize: Long) {
|
||||||
if (this.usedBytes + newSize > this.capacity)
|
// if (this.usedBytes + newSize > this.capacity)
|
||||||
throw IOException("Not enough space on the disk")
|
// throw IOException("Not enough space on the disk")
|
||||||
}
|
}
|
||||||
fun ByteArray64.toIntBig(): Int {
|
fun ByteArray64.toIntBig(): Int {
|
||||||
if (this.size != 4L)
|
if (this.size != 4L)
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ Version 254 is a customised version of TEVD tailored to be used as a savegame fo
|
|||||||
Int8 Disk properties flag 1
|
Int8 Disk properties flag 1
|
||||||
0th bit: readonly
|
0th bit: readonly
|
||||||
Int8 Save type (0b 0000 00ab)
|
Int8 Save type (0b 0000 00ab)
|
||||||
b: unset - full save; set - quick save
|
b: unset - full save; set - quicksave (only applicable to worlds -- quicksave just means the disk is in dirty state)
|
||||||
a: set - generated by autosave
|
a: set - generated by autosave
|
||||||
Int8 Kind of the Save file
|
Int8 Kind of the Save file
|
||||||
0: Undefined (or very old version of the game)
|
0: Undefined (or very old version of the game)
|
||||||
@@ -145,9 +145,7 @@ class VirtualDisk(
|
|||||||
|
|
||||||
var extraInfoBytes = ByteArray(16)
|
var extraInfoBytes = ByteArray(16)
|
||||||
val entries = HashMap<EntryID, DiskEntry>()
|
val entries = HashMap<EntryID, DiskEntry>()
|
||||||
var isReadOnly: Boolean
|
val isReadOnly = false
|
||||||
set(value) { extraInfoBytes[0] = (extraInfoBytes[0] and 0xFE.toByte()) or value.toBit() }
|
|
||||||
get() = capacity == 0L || (extraInfoBytes.size > 0 && extraInfoBytes[0].and(1) == 1.toByte())
|
|
||||||
var saveMode: Int
|
var saveMode: Int
|
||||||
set(value) { extraInfoBytes[1] = value.toByte() }
|
set(value) { extraInfoBytes[1] = value.toByte() }
|
||||||
get() = extraInfoBytes[1].toUint()
|
get() = extraInfoBytes[1].toUint()
|
||||||
@@ -260,6 +258,7 @@ object VDFileID {
|
|||||||
const val SPRITEDEF = -2L
|
const val SPRITEDEF = -2L
|
||||||
const val SPRITEDEF_GLOW = -3L
|
const val SPRITEDEF_GLOW = -3L
|
||||||
const val LOADORDER = -4L
|
const val LOADORDER = -4L
|
||||||
|
const val PLAYER_SCREENSHOT = -5L
|
||||||
const val BODYPART_TO_ENTRY_MAP = -1025L
|
const val BODYPART_TO_ENTRY_MAP = -1025L
|
||||||
const val BODYPARTGLOW_TO_ENTRY_MAP = -1026L
|
const val BODYPARTGLOW_TO_ENTRY_MAP = -1026L
|
||||||
}
|
}
|
||||||
@@ -279,6 +278,11 @@ fun diskIDtoReadableFilename(id: EntryID, saveKind: Int?): String = when (id) {
|
|||||||
"spritedef-glow"
|
"spritedef-glow"
|
||||||
else
|
else
|
||||||
"file #$id"
|
"file #$id"
|
||||||
|
VDFileID.PLAYER_SCREENSHOT ->
|
||||||
|
if (saveKind == PLAYER_DATA)
|
||||||
|
"screenshot.tga.gz"
|
||||||
|
else
|
||||||
|
"file #$id"
|
||||||
VDFileID.LOADORDER -> "loadOrder.txt"
|
VDFileID.LOADORDER -> "loadOrder.txt"
|
||||||
// -16L -> "blockcodex.json.gz"
|
// -16L -> "blockcodex.json.gz"
|
||||||
// -17L -> "itemcodex.json.gz"
|
// -17L -> "itemcodex.json.gz"
|
||||||
|
|||||||
@@ -415,41 +415,6 @@ class VirtualDiskCracker(val sysCharset: Charset = Charsets.UTF_8) : JFrame() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
menuEdit.add("Resize Disk…").addMouseListener(object : MouseAdapter() {
|
|
||||||
override fun mousePressed(e: MouseEvent?) {
|
|
||||||
if (vdisk != null) {
|
|
||||||
try {
|
|
||||||
val dialog = OptionSize()
|
|
||||||
val confirmed = dialog.showDialog("Input") == JOptionPane.OK_OPTION
|
|
||||||
if (confirmed) {
|
|
||||||
vdisk!!.capacity = (dialog.capacity.value as Long).toLong()
|
|
||||||
updateDiskInfo()
|
|
||||||
setStat("Disk resized")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
popupError(e.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
menuEdit.addSeparator()
|
|
||||||
menuEdit.add("Set/Unset Write Protection").addMouseListener(object : MouseAdapter() {
|
|
||||||
override fun mousePressed(e: MouseEvent?) {
|
|
||||||
if (vdisk != null) {
|
|
||||||
try {
|
|
||||||
vdisk!!.isReadOnly = vdisk!!.isReadOnly.not()
|
|
||||||
updateDiskInfo()
|
|
||||||
setStat("Disk write protection ${if (vdisk!!.isReadOnly) "" else "dis"}engaged")
|
|
||||||
}
|
|
||||||
catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
popupError(e.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
menuBar.add(menuEdit)
|
menuBar.add(menuEdit)
|
||||||
|
|
||||||
val menuManage = JMenu("Manage")
|
val menuManage = JMenu("Manage")
|
||||||
@@ -638,8 +603,7 @@ class VirtualDiskCracker(val sysCharset: Charset = Charsets.UTF_8) : JFrame() {
|
|||||||
}
|
}
|
||||||
private fun getDiskInfoText(disk: VirtualDisk): String {
|
private fun getDiskInfoText(disk: VirtualDisk): String {
|
||||||
return """Name: ${String(disk.diskName, sysCharset)}
|
return """Name: ${String(disk.diskName, sysCharset)}
|
||||||
Capacity: ${disk.capacity} bytes (${disk.usedBytes} bytes used, ${disk.capacity - disk.usedBytes} bytes free)
|
Capacity: ${disk.capacity} bytes (${disk.usedBytes} bytes used, ${disk.capacity - disk.usedBytes} bytes free)"""
|
||||||
Write protected: ${disk.isReadOnly.toEnglish()}"""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ class DummyTogglePane : UICanvas() {
|
|||||||
private var timer = 0f
|
private var timer = 0f
|
||||||
|
|
||||||
init {
|
init {
|
||||||
button1.clickOnceListener = { _,_,_ ->
|
button1.clickOnceListener = { _,_ ->
|
||||||
button1.toggle()
|
button1.toggle()
|
||||||
}
|
}
|
||||||
uiItems.add(button1)
|
uiItems.add(button1)
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ class BasicDebugInfoWindow : UICanvas() {
|
|||||||
|
|
||||||
blendNormalStraightAlpha(batch)
|
blendNormalStraightAlpha(batch)
|
||||||
|
|
||||||
batch.end()
|
/*batch.end()
|
||||||
gdxBlendNormalStraightAlpha()
|
gdxBlendNormalStraightAlpha()
|
||||||
Terrarum.inShapeRenderer {
|
Terrarum.inShapeRenderer {
|
||||||
it.color = uiColour
|
it.color = uiColour
|
||||||
@@ -388,7 +388,7 @@ class BasicDebugInfoWindow : UICanvas() {
|
|||||||
it.line(uiX + halfW, App.scr.height - (uiY + halfH), uiX + halfW + pointDX, App.scr.height - (uiY + halfH + pointDY))
|
it.line(uiX + halfW, App.scr.height - (uiY + halfH), uiX + halfW + pointDX, App.scr.height - (uiY + halfH + pointDY))
|
||||||
it.color = Color.GRAY
|
it.color = Color.GRAY
|
||||||
}
|
}
|
||||||
batch.begin()
|
batch.begin()*/
|
||||||
|
|
||||||
App.fontSmallNumbers.draw(batch, gamepad.getName(), Toolkit.drawWidth - (gamepad.getName().length + 2f) * TinyAlphNum.W, uiY.toFloat() + h + 2)
|
App.fontSmallNumbers.draw(batch, gamepad.getName(), Toolkit.drawWidth - (gamepad.getName().length + 2f) * TinyAlphNum.W, uiY.toFloat() + h + 2)
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class ConsoleWindow : UICanvas() {
|
|||||||
init {
|
init {
|
||||||
reset()
|
reset()
|
||||||
addUIitem(textinput)
|
addUIitem(textinput)
|
||||||
textinput.isActive = false
|
textinput.isEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private val lb = ArrayList<String>()
|
private val lb = ArrayList<String>()
|
||||||
@@ -99,7 +99,7 @@ class ConsoleWindow : UICanvas() {
|
|||||||
clickLatched = false
|
clickLatched = false
|
||||||
}
|
}
|
||||||
|
|
||||||
textinput.isActive = (isOpened && !isClosing)
|
textinput.isEnabled = (isOpened && !isClosing)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||||
@@ -269,14 +269,14 @@ class ConsoleWindow : UICanvas() {
|
|||||||
drawOffY = MovementInterpolator.fastPullOut(openingTimeCounter.toFloat() / openCloseTime.toFloat(),
|
drawOffY = MovementInterpolator.fastPullOut(openingTimeCounter.toFloat() / openCloseTime.toFloat(),
|
||||||
0f, -height.toFloat()
|
0f, -height.toFloat()
|
||||||
)*/
|
)*/
|
||||||
textinput.isActive = false
|
textinput.isEnabled = false
|
||||||
textinput.mouseoverUpdateLatch = false
|
textinput.mouseoverUpdateLatch = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun endOpening(delta: Float) {
|
override fun endOpening(delta: Float) {
|
||||||
drawOffY = 0f
|
drawOffY = 0f
|
||||||
openingTimeCounter = 0f
|
openingTimeCounter = 0f
|
||||||
textinput.isActive = true
|
textinput.isEnabled = true
|
||||||
textinput.mouseoverUpdateLatch = true
|
textinput.mouseoverUpdateLatch = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.torvald.terrarum.ui
|
|||||||
|
|
||||||
import com.badlogic.gdx.Gdx
|
import com.badlogic.gdx.Gdx
|
||||||
import com.badlogic.gdx.graphics.*
|
import com.badlogic.gdx.graphics.*
|
||||||
|
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||||
import com.badlogic.gdx.graphics.glutils.FloatFrameBuffer
|
import com.badlogic.gdx.graphics.glutils.FloatFrameBuffer
|
||||||
@@ -9,6 +10,7 @@ import com.badlogic.gdx.utils.Disposable
|
|||||||
import com.jme3.math.FastMath
|
import com.jme3.math.FastMath
|
||||||
import net.torvald.random.HQRNG
|
import net.torvald.random.HQRNG
|
||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
|
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap
|
||||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@@ -28,6 +30,8 @@ object Toolkit : Disposable {
|
|||||||
val COL_SELECTED = Color(0x00f8ff_ff) // cyan, HIGHLY SATURATED
|
val COL_SELECTED = Color(0x00f8ff_ff) // cyan, HIGHLY SATURATED
|
||||||
val COL_MOUSE_UP = Color(0xfff066_ff.toInt()) // yellow (all yellows are of low saturation according to the colour science)
|
val COL_MOUSE_UP = Color(0xfff066_ff.toInt()) // yellow (all yellows are of low saturation according to the colour science)
|
||||||
val COL_DISABLED = Color(0xaaaaaaff.toInt())
|
val COL_DISABLED = Color(0xaaaaaaff.toInt())
|
||||||
|
val COL_RED = Color(0xff8888ff.toInt())
|
||||||
|
val COL_REDD = Color(0xff4448ff.toInt())
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Try this for alt colour set:
|
Try this for alt colour set:
|
||||||
@@ -93,6 +97,10 @@ object Toolkit : Disposable {
|
|||||||
get() = App.scr.width - if (App.getConfigBoolean("fx_streamerslayout")) App.scr.chatWidth else 0
|
get() = App.scr.width - if (App.getConfigBoolean("fx_streamerslayout")) App.scr.chatWidth else 0
|
||||||
val drawWidthf: Float
|
val drawWidthf: Float
|
||||||
get() = drawWidth.toFloat()
|
get() = drawWidth.toFloat()
|
||||||
|
val hdrawWidth: Int
|
||||||
|
get() = drawWidth / 2
|
||||||
|
val hdrawWidthf: Float
|
||||||
|
get() = hdrawWidth.toFloat()
|
||||||
|
|
||||||
fun drawCentered(batch: SpriteBatch, image: Texture, screenPosY: Int, ui: UICanvas? = null) {
|
fun drawCentered(batch: SpriteBatch, image: Texture, screenPosY: Int, ui: UICanvas? = null) {
|
||||||
val imageW = image.width
|
val imageW = image.width
|
||||||
@@ -114,6 +122,11 @@ object Toolkit : Disposable {
|
|||||||
batch.draw(image, targetW.minus(imageW).ushr(1).toFloat() + offsetX, screenPosY.toFloat() + offsetY)
|
batch.draw(image, targetW.minus(imageW).ushr(1).toFloat() + offsetX, screenPosY.toFloat() + offsetY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun drawTextCentered(batch: SpriteBatch, font: TerrarumSansBitmap, text: String, tbw: Int, tbx: Int, tby: Int) {
|
||||||
|
val tw = font.getWidth(text)
|
||||||
|
font.draw(batch, text, tbx + (tbw - tw) / 2, tby)
|
||||||
|
}
|
||||||
|
|
||||||
fun fillArea(batch: SpriteBatch, x: Int, y: Int, w: Int, h: Int) {
|
fun fillArea(batch: SpriteBatch, x: Int, y: Int, w: Int, h: Int) {
|
||||||
batch.draw(textureWhiteSquare, x.toFloat(), y.toFloat(), w.toFloat(), h.toFloat())
|
batch.draw(textureWhiteSquare, x.toFloat(), y.toFloat(), w.toFloat(), h.toFloat())
|
||||||
}
|
}
|
||||||
@@ -250,7 +263,7 @@ object Toolkit : Disposable {
|
|||||||
(batch as FlippingSpriteBatch).drawFlipped(fboBlur.colorBufferTexture, x.toFloat(), y.toFloat())
|
(batch as FlippingSpriteBatch).drawFlipped(fboBlur.colorBufferTexture, x.toFloat(), y.toFloat())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun drawBaloon(batch: SpriteBatch, x: Float, y: Float, w: Float, h: Float) {
|
fun drawBaloon(batch: SpriteBatch, x: Float, y: Float, w: Float, h: Float, opacity: Float = 1f) {
|
||||||
// centre area
|
// centre area
|
||||||
/*batch.draw(baloonTile.get(1, 1), x, y, w, h)
|
/*batch.draw(baloonTile.get(1, 1), x, y, w, h)
|
||||||
|
|
||||||
@@ -267,9 +280,9 @@ object Toolkit : Disposable {
|
|||||||
batch.draw(baloonTile.get(0, 2), x - baloonTile.tileW, y + h)*/
|
batch.draw(baloonTile.get(0, 2), x - baloonTile.tileW, y + h)*/
|
||||||
|
|
||||||
|
|
||||||
batch.color = Theme.COL_CELL_FILL_OPAQUE
|
batch.color = Theme.COL_CELL_FILL_OPAQUE.cpy().mul(1f,1f,1f,opacity)
|
||||||
fillArea(batch, x - 4, y - 4, w + 8, h + 8)
|
fillArea(batch, x - 4, y - 4, w + 8, h + 8)
|
||||||
batch.color = Theme.COL_INACTIVE
|
batch.color = Theme.COL_INACTIVE.cpy().mul(1f,1f,1f,opacity)
|
||||||
drawBoxBorder(batch, x - 4, y - 4, w + 8, h + 8)
|
drawBoxBorder(batch, x - 4, y - 4, w + 8, h + 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class UIAutosaveNotifier : UICanvas() {
|
|||||||
private var errored = false
|
private var errored = false
|
||||||
|
|
||||||
private var normalCol = Color.WHITE
|
private var normalCol = Color.WHITE
|
||||||
private var errorCol = Color(0xFF8888FF.toInt())
|
private var errorCol = Toolkit.Theme.COL_RED
|
||||||
|
|
||||||
override fun updateUI(delta: Float) {
|
override fun updateUI(delta: Float) {
|
||||||
spinnerTimer += delta
|
spinnerTimer += delta
|
||||||
|
|||||||
@@ -128,9 +128,15 @@ abstract class UICanvas(
|
|||||||
|
|
||||||
|
|
||||||
/** A function that is run ONCE when the UI is requested to be opened; will work identical to [endOpening] if [openCloseTime] is zero */
|
/** A function that is run ONCE when the UI is requested to be opened; will work identical to [endOpening] if [openCloseTime] is zero */
|
||||||
open fun show() {}
|
open fun show() {
|
||||||
|
uiItems.forEach { it.show() }
|
||||||
|
handler.subUIs.forEach { it.show() }
|
||||||
|
}
|
||||||
/** A function that is run ONCE when the UI is requested to be closed; will work identical to [endClosing] if [openCloseTime] is zero */
|
/** A function that is run ONCE when the UI is requested to be closed; will work identical to [endClosing] if [openCloseTime] is zero */
|
||||||
open fun hide() {}
|
open fun hide() {
|
||||||
|
uiItems.forEach { it.hide() }
|
||||||
|
handler.subUIs.forEach { it.hide() }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** **DO NOT CALL THIS FUNCTION FOR THE ACTUAL UPDATING OF THE UI — USE update() INSTEAD**
|
/** **DO NOT CALL THIS FUNCTION FOR THE ACTUAL UPDATING OF THE UI — USE update() INSTEAD**
|
||||||
@@ -184,7 +190,7 @@ abstract class UICanvas(
|
|||||||
if (!uiItems.contains(uiItem)) uiItems.add(uiItem)
|
if (!uiItems.contains(uiItem)) uiItems.add(uiItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun mouseInScreen(x: Int, y: Int) = x in 0 until App.scr.width && y in 0 until App.scr.height
|
fun mouseInScreen(x: Int, y: Int) = x in 0 until App.scr.windowW && y in 0 until App.scr.windowH
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the screen's InputProcessor
|
* Called by the screen's InputProcessor
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package net.torvald.terrarum.ui
|
|||||||
import com.badlogic.gdx.graphics.Camera
|
import com.badlogic.gdx.graphics.Camera
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
import com.badlogic.gdx.utils.Disposable
|
import com.badlogic.gdx.utils.Disposable
|
||||||
|
import net.torvald.terrarum.App
|
||||||
import net.torvald.terrarum.Terrarum
|
import net.torvald.terrarum.Terrarum
|
||||||
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
|
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
|
||||||
|
|
||||||
@@ -95,31 +96,33 @@ abstract class UIItem(var parentUI: UICanvas, val initialX: Int, val initialY: I
|
|||||||
protected var mouseLatched = Terrarum.mouseDown
|
protected var mouseLatched = Terrarum.mouseDown
|
||||||
|
|
||||||
/** UI to call (show up) while mouse is up */
|
/** UI to call (show up) while mouse is up */
|
||||||
open val mouseOverCall: UICanvas? = null
|
open var mouseOverCall: UICanvas? = null
|
||||||
|
|
||||||
|
|
||||||
// kind of listener implementation
|
// kind of listener implementation
|
||||||
/** Fired once for every update
|
/** Fired once for every update
|
||||||
* Parameter: delta */
|
* Parameter: delta */
|
||||||
open var updateListener: ((Float) -> Unit)? = null
|
open var updateListener: ((Float) -> Unit) = {}
|
||||||
/** Parameter: keycode */
|
/** Parameter: keycode */
|
||||||
open var keyDownListener: ((Int) -> Unit)? = null
|
open var keyDownListener: ((Int) -> Unit) = {}
|
||||||
/** Parameter: keycode */
|
/** Parameter: keycode */
|
||||||
open var keyUpListener: ((Int) -> Unit)? = null
|
open var keyUpListener: ((Int) -> Unit) = {}
|
||||||
open var keyTypedListener: ((Char) -> Unit)? = null
|
open var keyTypedListener: ((Char) -> Unit) = {}
|
||||||
open var touchDraggedListener: ((Int, Int, Int) -> Unit)? = null
|
open var touchDraggedListener: ((Int, Int, Int) -> Unit) = { _,_,_ -> }
|
||||||
/** Parameters: screenX, screenY, pointer, button */
|
/** Parameters: screenX, screenY, pointer, button */
|
||||||
open var touchDownListener: ((Int, Int, Int, Int) -> Unit)? = null
|
@Deprecated("Not really deprecated but you MOST DEFINITELY want to use clickOnceListener(mouseX, mouseY) instead.")
|
||||||
open var touchUpListener: ((Int, Int, Int, Int) -> Unit)? = null
|
open var touchDownListener: ((Int, Int, Int, Int) -> Unit) = { _,_,_,_ -> }
|
||||||
|
open var touchUpListener: ((Int, Int, Int, Int) -> Unit) = { _,_,_,_ -> }
|
||||||
/** Parameters: amountX, amountY */
|
/** Parameters: amountX, amountY */
|
||||||
open var scrolledListener: ((Float, Float) -> Unit)? = null
|
open var scrolledListener: ((Float, Float) -> Unit) = { _,_ -> }
|
||||||
/** Parameters: relative mouseX, relative mouseY, button
|
/** Parameters: relative mouseX, relative mouseY
|
||||||
*
|
* ClickOnce listeners are only fired when clicked with primary mouse button
|
||||||
* PROTIP: if clickOnceListener does not seem to work, make sure your parent UI is handling touchDown() and touchUp() events!
|
* PROTIP: if clickOnceListener does not seem to work, make sure your parent UI is handling touchDown() and touchUp() events!
|
||||||
*/
|
*/
|
||||||
open var clickOnceListener: ((Int, Int, Int) -> Unit)? = null
|
open var clickOnceListener: ((Int, Int) -> Unit) = { _,_ -> }
|
||||||
open var clickOnceListenerFired = false
|
open var clickOnceListenerFired = false
|
||||||
|
/** Parameters: relative mouseX, mouseY */
|
||||||
|
open var mouseUpListener: ((Int, Int) -> Unit) = { _,_, -> }
|
||||||
|
|
||||||
/** Since gamepads can't just choose which UIItem to control, this variable is used to allow processing of
|
/** Since gamepads can't just choose which UIItem to control, this variable is used to allow processing of
|
||||||
* gamepad button events for one or more UIItems in one or more UICanvases. */
|
* gamepad button events for one or more UIItems in one or more UICanvases. */
|
||||||
@@ -128,6 +131,11 @@ abstract class UIItem(var parentUI: UICanvas, val initialX: Int, val initialY: I
|
|||||||
/**
|
/**
|
||||||
* Whether the button is "available" or not to the player
|
* Whether the button is "available" or not to the player
|
||||||
*/
|
*/
|
||||||
|
open var isEnabled = true
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the button should receive updates
|
||||||
|
*/
|
||||||
open var isActive = true
|
open var isActive = true
|
||||||
|
|
||||||
|
|
||||||
@@ -137,28 +145,27 @@ abstract class UIItem(var parentUI: UICanvas, val initialX: Int, val initialY: I
|
|||||||
|
|
||||||
open fun update(delta: Float) {
|
open fun update(delta: Float) {
|
||||||
if (parentUI.isVisible) {
|
if (parentUI.isVisible) {
|
||||||
if (updateListener != null) {
|
|
||||||
updateListener!!.invoke(delta)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
|
updateListener.invoke(delta)
|
||||||
|
|
||||||
mouseOverCall?.update(delta)
|
mouseOverCall?.update(delta)
|
||||||
|
|
||||||
if (mouseUp) {
|
if (mouseUp) {
|
||||||
if (mouseOverCall?.isVisible ?: false) {
|
if (mouseOverCall?.isVisible == true) {
|
||||||
mouseOverCall?.setAsOpen()
|
mouseOverCall?.setAsOpen()
|
||||||
}
|
}
|
||||||
|
|
||||||
mouseOverCall?.updateUI(delta)
|
mouseOverCall?.updateUI(delta)
|
||||||
|
mouseUpListener.invoke(itemRelativeMouseX, itemRelativeMouseY)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (mouseOverCall?.isVisible ?: false) {
|
if (mouseOverCall?.isVisible == true) {
|
||||||
mouseOverCall?.setAsClose()
|
mouseOverCall?.setAsClose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!mouseUp) mouseLatched = false
|
if (!mouseUp) mouseLatched = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,36 +174,36 @@ abstract class UIItem(var parentUI: UICanvas, val initialX: Int, val initialY: I
|
|||||||
*/
|
*/
|
||||||
open fun render(batch: SpriteBatch, camera: Camera) {
|
open fun render(batch: SpriteBatch, camera: Camera) {
|
||||||
if (parentUI.isVisible) {
|
if (parentUI.isVisible) {
|
||||||
if (isActive) {
|
// if (isActive) {
|
||||||
mouseOverCall?.render(batch, camera)
|
mouseOverCall?.render(batch, camera)
|
||||||
|
|
||||||
if (mouseUp) {
|
if (mouseUp) {
|
||||||
mouseOverCall?.renderUI(batch, camera)
|
mouseOverCall?.renderUI(batch, camera)
|
||||||
}
|
}
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// keyboard controlled
|
// keyboard controlled
|
||||||
open fun keyDown(keycode: Int): Boolean {
|
open fun keyDown(keycode: Int): Boolean {
|
||||||
if (parentUI.isVisible && keyDownListener != null && isActive) {
|
if (parentUI.isVisible && isEnabled) {
|
||||||
keyDownListener!!.invoke(keycode)
|
keyDownListener.invoke(keycode)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
open fun keyUp(keycode: Int): Boolean {
|
open fun keyUp(keycode: Int): Boolean {
|
||||||
if (parentUI.isVisible && keyUpListener != null && isActive) {
|
if (parentUI.isVisible && isEnabled) {
|
||||||
keyUpListener!!.invoke(keycode)
|
keyUpListener.invoke(keycode)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
open fun keyTyped(character: Char): Boolean {
|
open fun keyTyped(character: Char): Boolean {
|
||||||
if (parentUI.isVisible && keyTypedListener != null && isActive) {
|
if (parentUI.isVisible && isEnabled) {
|
||||||
keyTypedListener!!.invoke(character)
|
keyTypedListener.invoke(character)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,8 +212,8 @@ abstract class UIItem(var parentUI: UICanvas, val initialX: Int, val initialY: I
|
|||||||
|
|
||||||
// mouse controlled
|
// mouse controlled
|
||||||
open fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
|
open fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
|
||||||
if (parentUI.isVisible && touchDraggedListener != null && isActive) {
|
if (parentUI.isVisible && isEnabled) {
|
||||||
touchDraggedListener!!.invoke(itemRelativeMouseX, itemRelativeMouseY, pointer)
|
touchDraggedListener.invoke(itemRelativeMouseX, itemRelativeMouseY, pointer)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,14 +222,14 @@ abstract class UIItem(var parentUI: UICanvas, val initialX: Int, val initialY: I
|
|||||||
open fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
open fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||||
var actionDone = false
|
var actionDone = false
|
||||||
|
|
||||||
if (parentUI.isVisible && isActive) {
|
if (parentUI.isVisible && isEnabled) {
|
||||||
if (touchDownListener != null && mouseUp) {
|
if (mouseUp) {
|
||||||
touchDownListener!!.invoke(itemRelativeMouseX, itemRelativeMouseY, pointer, button)
|
touchDownListener.invoke(itemRelativeMouseX, itemRelativeMouseY, pointer, button)
|
||||||
actionDone = true
|
actionDone = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clickOnceListener != null && !clickOnceListenerFired && mouseUp) {
|
if (!clickOnceListenerFired && mouseUp && button == App.getConfigInt("config_mouseprimary")) {
|
||||||
clickOnceListener!!.invoke(itemRelativeMouseX, itemRelativeMouseY, button)
|
clickOnceListener.invoke(itemRelativeMouseX, itemRelativeMouseY)
|
||||||
actionDone = true
|
actionDone = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,16 +239,16 @@ abstract class UIItem(var parentUI: UICanvas, val initialX: Int, val initialY: I
|
|||||||
open fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
open fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||||
clickOnceListenerFired = false
|
clickOnceListenerFired = false
|
||||||
|
|
||||||
if (parentUI.isVisible && touchUpListener != null && mouseUp) {
|
if (parentUI.isVisible && mouseUp) {
|
||||||
touchUpListener!!.invoke(itemRelativeMouseX, itemRelativeMouseY, pointer, button)
|
touchUpListener.invoke(itemRelativeMouseX, itemRelativeMouseY, pointer, button)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
open fun scrolled(amountX: Float, amountY: Float): Boolean {
|
open fun scrolled(amountX: Float, amountY: Float): Boolean {
|
||||||
if (parentUI.isVisible && scrolledListener != null && mouseUp && isActive) {
|
if (parentUI.isVisible && mouseUp && isEnabled) {
|
||||||
scrolledListener!!.invoke(amountX, amountY)
|
scrolledListener.invoke(amountX, amountY)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class UIItemHorizontalFadeSlide(
|
|||||||
//transitionLength: Float,
|
//transitionLength: Float,
|
||||||
currentPosition: Float,
|
currentPosition: Float,
|
||||||
vararg uis: UICanvas
|
vararg uis: UICanvas
|
||||||
) : UIItemTransitionContainer(parent, initialX, initialY, width, height, 0.10f, currentPosition, uis) {
|
) : UIItemTransitionContainer(parent, initialX, initialY, width, height, 0.12f, currentPosition, uis) {
|
||||||
|
|
||||||
fun getOffX(index: Int) = ((currentPosition - index) * width / 2f).roundToInt()
|
fun getOffX(index: Int) = ((currentPosition - index) * width / 2f).roundToInt()
|
||||||
fun getOpacity(index: Int) = 1f - (currentPosition - index).absoluteValue.coerceIn(0f, 1f)
|
fun getOpacity(index: Int) = 1f - (currentPosition - index).absoluteValue.coerceIn(0f, 1f)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.badlogic.gdx.graphics.Color
|
|||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||||
import net.torvald.terrarum.BlendMode
|
import net.torvald.terrarum.BlendMode
|
||||||
|
import net.torvald.terrarum.abs
|
||||||
import net.torvald.terrarum.blendNormalStraightAlpha
|
import net.torvald.terrarum.blendNormalStraightAlpha
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,14 +34,24 @@ open class UIItemImageButton(
|
|||||||
|
|
||||||
initialX: Int,
|
initialX: Int,
|
||||||
initialY: Int,
|
initialY: Int,
|
||||||
|
/** this does NOT resize the image; use imageDrawWidth to actually resize the image */
|
||||||
override val width: Int = image.regionWidth,
|
override val width: Int = image.regionWidth,
|
||||||
|
/** this does NOT resize the image; use imageDrawHeight to actually resize the image */
|
||||||
override val height: Int = image.regionHeight,
|
override val height: Int = image.regionHeight,
|
||||||
|
|
||||||
/** When clicked, toggle its "lit" status */
|
/** When clicked, toggle its "lit" status */
|
||||||
var highlightable: Boolean
|
var highlightable: Boolean,
|
||||||
|
/** Changes the appearance to use a border instead of colour-changing image for highlighter */
|
||||||
|
val useBorder: Boolean = false,
|
||||||
|
|
||||||
|
/** Image won't be place at right position if `image.regionWidth != imageDrawWidth`; define the `width` argument to avoid the issue */
|
||||||
|
val imageDrawWidth: Int = image.regionWidth,
|
||||||
|
/** Image won't be place at right position if `image.regionHeight != imageDrawHeight`; define the `height` argument to avoid the issue */
|
||||||
|
val imageDrawHeight: Int = image.regionHeight,
|
||||||
) : UIItem(parent, initialX, initialY) {
|
) : UIItem(parent, initialX, initialY) {
|
||||||
|
|
||||||
var highlighted = false
|
var highlighted = false
|
||||||
|
var extraDrawOp: (UIItem, SpriteBatch) -> Unit = { _,_ -> }
|
||||||
|
|
||||||
override fun render(batch: SpriteBatch, camera: Camera) {
|
override fun render(batch: SpriteBatch, camera: Camera) {
|
||||||
// draw background
|
// draw background
|
||||||
@@ -60,15 +71,22 @@ open class UIItemImageButton(
|
|||||||
Toolkit.fillArea(batch, posX.toFloat(), posY.toFloat(), width.toFloat(), height.toFloat())
|
Toolkit.fillArea(batch, posX.toFloat(), posY.toFloat(), width.toFloat(), height.toFloat())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blendNormalStraightAlpha(batch)
|
||||||
|
|
||||||
// draw image
|
// draw image
|
||||||
blendNormalStraightAlpha(batch)
|
batch.color = if (highlighted) highlightCol
|
||||||
|
else if (mouseUp) activeCol
|
||||||
|
else if (useBorder) Toolkit.Theme.COL_INACTIVE else inactiveCol
|
||||||
|
if (useBorder) {
|
||||||
|
Toolkit.drawBoxBorder(batch, posX - 1f, posY - 1f, width + 2f, height + 2f)
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
}
|
||||||
|
batch.draw(image, (posX + (width - imageDrawWidth) / 2).toFloat(), (posY + (height - imageDrawHeight) / 2).toFloat(), imageDrawWidth.toFloat(), imageDrawHeight.toFloat())
|
||||||
|
|
||||||
batch.color = if (highlighted) highlightCol
|
batch.color = if (highlighted) highlightCol
|
||||||
else if (mouseUp) activeCol
|
else if (mouseUp) activeCol
|
||||||
else inactiveCol
|
else inactiveCol
|
||||||
|
extraDrawOp(this, batch)
|
||||||
batch.draw(image, (posX + (width - image.regionWidth) / 2).toFloat(), (posY + (height - image.regionHeight) / 2).toFloat())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
|
|||||||
@@ -85,45 +85,6 @@ class UIItemIntSlider(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO unimplemented
|
|
||||||
|
|
||||||
|
|
||||||
override val mouseUp: Boolean
|
|
||||||
get() = super.mouseUp
|
|
||||||
override val mousePushed: Boolean
|
|
||||||
get() = super.mousePushed
|
|
||||||
override val mouseOverCall: UICanvas?
|
|
||||||
get() = super.mouseOverCall
|
|
||||||
override var updateListener: ((Float) -> Unit)?
|
|
||||||
get() = super.updateListener
|
|
||||||
set(_) {}
|
|
||||||
override var keyDownListener: ((Int) -> Unit)?
|
|
||||||
get() = super.keyDownListener
|
|
||||||
set(_) {}
|
|
||||||
override var keyUpListener: ((Int) -> Unit)?
|
|
||||||
get() = super.keyUpListener
|
|
||||||
set(_) {}
|
|
||||||
override var touchDraggedListener: ((Int, Int, Int) -> Unit)?
|
|
||||||
get() = super.touchDraggedListener
|
|
||||||
set(_) {}
|
|
||||||
override var touchDownListener: ((Int, Int, Int, Int) -> Unit)?
|
|
||||||
get() = super.touchDownListener
|
|
||||||
set(_) {}
|
|
||||||
override var touchUpListener: ((Int, Int, Int, Int) -> Unit)?
|
|
||||||
get() = super.touchUpListener
|
|
||||||
set(_) {}
|
|
||||||
override var scrolledListener: ((Float, Float) -> Unit)?
|
|
||||||
get() = super.scrolledListener
|
|
||||||
set(_) {}
|
|
||||||
override var clickOnceListener: ((Int, Int, Int) -> Unit)?
|
|
||||||
get() = super.clickOnceListener
|
|
||||||
set(_) {}
|
|
||||||
override var clickOnceListenerFired: Boolean
|
|
||||||
get() = super.clickOnceListenerFired
|
|
||||||
set(_) {}
|
|
||||||
override var controllerInFocus: Boolean
|
|
||||||
get() = super.controllerInFocus
|
|
||||||
set(_) {}
|
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user