Greek support, modular weather, command history for console window

Former-commit-id: b72d0b018c084e80cf4fef77e1b1a81101d6daea
Former-commit-id: 32da6a2998826de6519a901dcff7bf058f689b2f
This commit is contained in:
Song Minjae
2016-07-13 21:48:14 +09:00
parent c52015e429
commit 1d1f99605c
74 changed files with 1067 additions and 387 deletions

View File

@@ -0,0 +1,29 @@
"APP_WARNING_HEALTH_AND_SAFETY": ""
bgBG ВНИМАНИЕ-ЗДРАВЕ И БЕЗОПАСНОСТ
csCZ POZOR-ZDRAVÍ A BEZPEČNOST
daDK ADVARSEL-SUNDHED OG SIKKERHED
de WARNUNG-GESUNDHEIT UND SICHERHEIT
elGR ΠΡΟΣΟΧΗ-ΥΓΕΙΑ ΚΑΙ ΑΣΦΑΛΕΙΑ
en WARNING-HEALTH AND SAFETY
es ADVERTENCIA-SALUD Y SEGURIDAD
fiFI VAROITUS-TERVEYS JA TURVALLISUUS
fr ATTENTION-SANTÉ ET SÉCURITÉ
huHU VIGYÁZAT-EGÉSZSÉGÜGYI ÉS BIZTONSÁGI
isIC VIÐVÖRUN-HEILSA OG ÖRYGGI
it ATTENZIONE-SALUTE E SICUREZZA
jaJP 警告ー健康と安全のために
jakana けいこくーけんこうと あんぜんの ために
koKR 경고—건강과 안전을 위하여
nlNL WAARSCHUWING-GEZONDHEID EN VEILIGHEID
noNB ADVARSEL-HELSE OG SIKKERHET
plPL UWAGA-ZDROWIE I BEZPIECZEŃSTWO
ptBR ATENÇÃO-SAÚDE E SEGURANÇA
ptPT ATENÇÃO-SAÚDE E SEGURANÇA
roRO ATENȚIONARE-SĂNĂTATE ȘI SIGURANȚĂ
ruRU ПРЕДУПРЕЖДЕНИЕ-ЗДОРОВЬЕ И БЕЗОПАСНОСТЬ
svSE VARNING-HÄLSA OCH SÄKERHET
thTH คำเตือน-อนามัยและความปลอดภัย
trTR UYARI-SAĞLIK VE GÜVENLİK
zhCN 警告ー健康和安全
zhTW 警告ー健康和安全

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 934 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -4,6 +4,6 @@
"COPYRIGHT_ALL_RIGHTS_RESERVED": "ぜんちょさくけん しょゆう。",
"APP_ADJUST_YOUR_MONITOR": "このゲームは、てきせつにちょうせいした モニターから さいこうのプレイができます。ちょうせいして いなかったら、プレイするまえに ちょうせいしてください。",
"APP_WARNING_HEALTH_AND_SAFETY": "けいこくーけんこうと あんぜん ために"
"APP_WARNING_HEALTH_AND_SAFETY": "けいこくーけんこうと あんぜん ために"
}

View File

@@ -0,0 +1,46 @@
Creature raw documentation
## Physical properties ##
* 1 m = 24 px
* mult: Multiplier. e.g. 1.0, 0.85, 1.25, ...
|name|unit|description|
|----|----|-----------|
|baseheight|pixels|Base height for hitbox. Also used for attack point bonus calculation|
|basemass|kg|Base mass for creature|
|accel|px per TARGET_FPS^2|Acceleration for walking|
|speed|px per TARGET_FPS|Walk speed|
|jumppower|neg. px per TARGET_FPS^2|Self-explanatory|
|scale|unit|Creature body scale. Mass/strength/accel/etc. will be changed accordingly, hence the prefix “base” for some raw tokens|
|dragcoeff|unit|Drag coefficient|
|speedmult, accelmult, jumppowermult|array of percentiles (Int)|Variability factor|
|physiquemult|mult|Breadth variation for mobs|
## Creature properties ##
|name|unit|description|
|----|----|-----------|
|strength|unit|Strength value, no significant unit is given. The value for regular human is fixed to 1 000|
|encumbrance|kg or itemcount|Capacity of carrying|
|basedefence|unit|Base defence value of body. Sterner body composition (material) == higher value|
|armourdefence|unit|Current defence point of armour worn|
|armourdefencemult|mult|Bonus point for armour defence|
|toolsize|kg|Base tool size for the creature. See MECHANICS file for more information|
## Aesthetic properties ##
|name|unit|description|
|----|----|-----------|
|luminosity|30-bit RGB (Int)|Self-glow. Set to 0 for not glowing|
|name|String|Given (perhaps customised) name|
|racename|STRING_ID|Racename token in language CSV|
|racenameplural|STRING_ID|Racename token in language CSV|
* Note: luminosity uses customised 30-bit RGB. The format specifies ```1.0``` luminosity of white (```#FFFFFF```) be ```0000_0011111111_0011111111_0011111111```, and can hold luminosity range of 0.0-4.0
## Flags ##
|name|unit|description|
|----|----|-----------|
|intelligent|Boolean|Whether the creature can speak and talk.|

View File

@@ -1,27 +0,0 @@
Creature raw documentation
== string values ==
racename(plural) : Racename token in language CSV
baseheight : base height for hitbox. [px] (24 px == 1 metre)
basemass : base mass for creature. [kg]
== number values ==
strength : strength value, no significant unit is given. The value for regular human is fixed to 1 000.
accel : acceleration for walking. [px / TARGET_FPS^2]
speed : walk speed. [px / TARGET_FPS]
jumppower : self-explanatory. [-px / TARGET_FPS^2]
scale : creature body scale. Mass/strength/accel/etc. will be changed accordingly, hence the prefix “base” for some raw tokens.
-mass : variability factor. [array of percentiles]
encumbrance : capacity of carrying. [kg]
basedefence : base defence value of body. Sterner body material == higher value
toolsize : base tool size for the creature. See MECHANICS file for more information.
== boolean values ==
intelligent : can speak and talk.

View File

@@ -1,28 +1,28 @@
{
"racename" : "RACE_HUMAN",
"racenameplural" : "RACE_HUMAN_PLURAL",
"baseheight" : 40,
"basemass" : 60.0,
"racename": "RACE_HUMAN",
"racenameplural": "RACE_HUMAN_PLURAL",
"baseheight": 40,
"basemass": 60.0,
"strength" : 1000,
"strengthmult" : [100,100,100,100,100,100,100],
"strength": 1000,
"strengthmult": [100,100,100,100,100,100,100],
"accel" : 0.32,
"accel": 0.32,
"speed" : 3.0,
"speedmult" : [100,100,100,100,100,100,100],
"speed": 3.0,
"speedmult": [100,100,100,100,100,100,100],
"jumppower" : 4.3,
"jumppowermult" : [100,100,100,100,100,100,100],
"jumppower": 4.3,
"jumppowermult": [100,100,100,100,100,100,100],
"scale" : 1.0,
"scalemult" : [100,100,100,100,100,100,100],
"scale": 1.0,
"physiquemult": [100,100,100,100,100,100,100],
"encumbrance" : 1000,
"basedefence" : 100,
"encumbrance": 1000,
"basedefence": 100,
"toolsize" : 15,
"toolsize": 15,
"intelligent" : true
"intelligent": true
}

View File

@@ -0,0 +1,8 @@
{
"globalLight": "generic_light.png",
"skyboxGradColourMap": "generic_skybox.png",
"classification": "generic",
"extraImages": [
]
}

View File

@@ -0,0 +1,57 @@
package net.torvald.gadgets
import java.util.*
import java.util.function.Consumer
/**
* Simple ArrayList wrapper that acts as history keeper. You can append any data but cannot delete.
* Created by minjaesong on 16-07-13.
*/
class HistoryArray<T>(val historyMax: Int) {
val history = ArrayList<T?>(Math.min(historyMax, 256)) // 256: arbitrary-set upper bound
fun add(value: T) {
if (history.size == 0) {
history.add(value)
return
}
// push existing values to back 1 index
else {
for (i in history.size - 1 downTo 0) {
// if history.size is smaller than historyMax, make room by appending
if (i == history.size - 1 && i < historyMax - 1)
history.add(history[i])
// actually move if we have some room
else if (i < historyMax - 1)
history[i + 1] = history[i]
}
}
// add new value to the room
history[0] = value
}
/**
* Get certain index from history. NOTE: index 0 means latest!
*/
operator fun get(index: Int): T? =
if (index >= history.size) null
else history[index]
/**
* Iterate from latest to oldest
*/
fun iterator() = history.iterator()
/**
* Iterate from latest to oldest
*/
fun forEach(action: Consumer<T?>) = history.forEach(action)
val latest: T?
get() = this[0]
val oldest: T?
get() = this[history.size - 1]
}

View File

@@ -55,34 +55,22 @@ constructor() : Font {
}
private fun isAsciiEF(c: Char) = asciiEFList.contains(c)
private fun isExtAEF(c: Char) = extAEFList.contains(c)
private fun isHangul(c: Char) = c.toInt() >= 0xAC00 && c.toInt() < 0xD7A4
private fun isAscii(c: Char) = c.toInt() > 0x20 && c.toInt() <= 0xFF
private fun isRunic(c: Char) = runicList.contains(c)
private fun isExtA(c: Char) = c.toInt() >= 0x100 && c.toInt() < 0x180
private fun isKana(c: Char) = c.toInt() >= 0x3040 && c.toInt() < 0x3100
private fun isCJKPunct(c: Char) = c.toInt() >= 0x3000 && c.toInt() < 0x3040
private fun isUniHan(c: Char) = c.toInt() >= 0x3400 && c.toInt() < 0xA000
private fun isCyrilic(c: Char) = c.toInt() >= 0x400 && c.toInt() < 0x460
private fun isCyrilicEF(c: Char) = cyrilecEFList.contains(c)
private fun isFullwidthUni(c: Char) = c.toInt() >= 0xFF00 && c.toInt() < 0xFF20
private fun isUniPunct(c: Char) = c.toInt() >= 0x2000 && c.toInt() < 0x2070
private fun isWenQuanYi1(c: Char) = c.toInt() >= 0x33F3 && c.toInt() <= 0x69FC
private fun isWenQuanYi2(c: Char) = c.toInt() >= 0x69FD && c.toInt() <= 0x9FDC
private fun isGreek(c: Char) = c.toInt() >= 0x370 && c.toInt() <= 0x3CE
private fun isGreekEF(c: Char) = greekEFList.contains(c)
@@ -121,37 +109,65 @@ constructor() : Font {
private fun wenQuanYi1IndexY(c: Char) = (c.toInt() - (0x33F3 + 0x4A)) / 32
private fun wenQuanYi2IndexY(c: Char) = (c.toInt() - 0x69FD) / 32
override fun getWidth(s: String) = getWidthSubstr(s, s.length)
private fun greekIndexX(c: Char) = (c.toInt() - 0x370) % 16
private fun greekIndexY(c: Char) = (c.toInt() - 0x370) / 16
private fun greekEFIndexX(c: Char) = greekEFList.indexOf(c) % 16
private fun greekEFIndexY(c: Char) = greekEFList.indexOf(c) / 16
private val narrowWidthSheets = arrayOf(
SHEET_ASCII_EF,
SHEET_EXTA_EF,
SHEET_CYRILIC_EF,
SHEET_GREEK_EF
)
private val unihanWidthSheets = arrayOf(
SHEET_UNIHAN,
SHEET_FW_UNI,
SHEET_WENQUANYI_1,
SHEET_WENQUANYI_2
)
private val zeroWidthSheets = arrayOf(
SHEET_COLOURCODE
)
private val cjkWidthSheets = arrayOf(
SHEET_KANA,
SHEET_HANGUL,
SHEET_CJK_PUNCT
)
override fun getWidth(s: String) = getWidthSubstr(s, s.length)
private fun getWidthSubstr(s: String, endIndex: Int): Int {
var len = 0
for (i in 0..endIndex - 1) {
val c = getSheetType(s[i])
val ctype = getSheetType(s[i])
if (i > 0 && s[i].toInt() > 0x20) {
// Kerning
// Unihan-hangul Kerning
val cpre = getSheetType(s[i - 1])
if ((cpre == SHEET_UNIHAN || cpre == SHEET_HANGUL) && !(c == SHEET_UNIHAN || c == SHEET_HANGUL)
if ((unihanWidthSheets.contains(cpre) || cpre == SHEET_HANGUL) && !(unihanWidthSheets.contains(ctype) || ctype == SHEET_HANGUL)
|| (c == SHEET_UNIHAN || c == SHEET_HANGUL) && !(cpre == SHEET_UNIHAN || cpre == SHEET_HANGUL)) {
|| (unihanWidthSheets.contains(ctype) || ctype == SHEET_HANGUL) && !(unihanWidthSheets.contains(cpre) || cpre == SHEET_HANGUL)) {
// margin after/before hangul/unihan
len += 2
}
else if ((c == SHEET_HANGUL || c == SHEET_KANA) && (cpre == SHEET_HANGUL || cpre == SHEET_KANA)) {
else if ((ctype == SHEET_HANGUL || ctype == SHEET_KANA) && (cpre == SHEET_HANGUL || cpre == SHEET_KANA)) {
// margin between hangul/kana
len += 1
}
}
if (c == SHEET_COLOURCODE)
if (zeroWidthSheets.contains(ctype))
len += 0
else if (c == SHEET_ASCII_EF || c == SHEET_EXTA_EF || c == SHEET_CYRILIC_EF)
else if (narrowWidthSheets.contains(ctype))
len += W_LATIN_NARROW
else if (c == SHEET_KANA || c == SHEET_HANGUL || c == SHEET_CJK_PUNCT)
else if (cjkWidthSheets.contains(ctype))
len += W_CJK
else if (c == SHEET_UNIHAN || c == SHEET_FW_UNI || c == SHEET_WENQUANYI_1 || c == SHEET_WENQUANYI_2)
else if (unihanWidthSheets.contains(ctype))
len += W_UNIHAN
else
len += W_LATIN_WIDE
@@ -375,6 +391,14 @@ constructor() : Font {
sheetX = uniPunctIndexX(ch)
sheetY = uniPunctIndexY(ch)
}
SHEET_GREEK_EM -> {
sheetX = greekIndexX(ch)
sheetY = greekIndexY(ch)
}
SHEET_GREEK_EF -> {
sheetX = greekEFIndexX(ch)
sheetY = greekEFIndexY(ch)
}
else -> {
sheetX = ch.toInt() % 16
sheetY = ch.toInt() / 16
@@ -406,6 +430,10 @@ constructor() : Font {
catch (e: ArrayIndexOutOfBoundsException) {
// character that does not exist in the sheet. No render, pass.
}
catch (e1: RuntimeException) {
// System.err.println("[GameFontBase] RuntimeException raised while processing character '$ch' (U+${Integer.toHexString(ch.toInt()).toUpperCase()})")
// e1.printStackTrack()
}
}
}
@@ -424,6 +452,8 @@ constructor() : Font {
return SHEET_EXTA_EF
else if (isCyrilicEF(c))
return SHEET_CYRILIC_EF
else if (isGreekEF(c))
return SHEET_GREEK_EF
else if (isRunic(c))
return SHEET_RUNIC
else if (isHangul(c))
@@ -444,6 +474,8 @@ constructor() : Font {
return SHEET_CJK_PUNCT
else if (isFullwidthUni(c))
return SHEET_FW_UNI
else if (isGreek(c))
return SHEET_GREEK_EM
else if (c.isColourCode())
return SHEET_COLOURCODE
else
@@ -516,6 +548,8 @@ constructor() : Font {
lateinit internal var uniPunct: SpriteSheet
lateinit internal var wenQuanYi_1: SpriteSheet
lateinit internal var wenQuanYi_2: SpriteSheet
lateinit internal var greekSheet: SpriteSheet
lateinit internal var greekSheetEF: SpriteSheet
internal val JUNG_COUNT = 21
internal val JONG_COUNT = 28
@@ -544,12 +578,12 @@ constructor() : Font {
internal val SHEET_UNI_PUNCT = 12
internal val SHEET_WENQUANYI_1 = 13
internal val SHEET_WENQUANYI_2 = 14
internal val SHEET_GREEK_EM = 15
internal val SHEET_GREEK_EF = 16
internal val SHEET_COLOURCODE = 255
lateinit internal var sheetKey: Array<SpriteSheet>
internal val asciiEFList = arrayOf(' ', '!', '"', '\'', '(', ')', ',', '.', ':', ';', 'I', '[', ']', '`', 'f', 'i', 'j', 'l', 't', '{', '|', '}', 0xA1.toChar(), 'Ì', 'Í', 'Î', 'Ï', 'ì', 'í', 'î', 'ï', '·')
internal val extAEFList = arrayOf(
0x12E.toChar(),
0x12F.toChar(),
@@ -563,7 +597,6 @@ constructor() : Font {
0x167.toChar(),
0x17F.toChar()
)
internal val cyrilecEFList = arrayOf(
0x406.toChar(),
0x407.toChar(),
@@ -571,6 +604,14 @@ constructor() : Font {
0x457.toChar(),
0x458.toChar()
)
internal val greekEFList = arrayOf(
0x390.toChar(),
0x399.toChar(),
0x3AA.toChar(),
0x3AF.toChar(),
0x3B9.toChar(),
0x3CA.toChar()
)
/**
* Runic letters list used for game. The set is

View File

@@ -46,6 +46,10 @@ constructor() : GameFontBase() {
"./res/graphics/fonts/wenquanyi_11pt_part1.png", 16, 18, 2)
GameFontBase.wenQuanYi_2 = SpriteSheet(
"./res/graphics/fonts/wenquanyi_11pt_part2.png", 16, 18, 2)
GameFontBase.greekSheet = SpriteSheet(
"./res/graphics/fonts/greek_majuscule.png", GameFontBase.W_LATIN_WIDE, GameFontBase.H)
GameFontBase.greekSheetEF = SpriteSheet(
"./res/graphics/fonts/greek_ef.png", GameFontBase.W_LATIN_NARROW, GameFontBase.H)
val shk = arrayOf(
GameFontBase.asciiSheet,
@@ -62,7 +66,10 @@ constructor() : GameFontBase() {
GameFontBase.fullwidthForms,
GameFontBase.uniPunct,
GameFontBase.wenQuanYi_1,
GameFontBase.wenQuanYi_2)//, uniHan
GameFontBase.wenQuanYi_2, // uniHan
GameFontBase.greekSheet,
GameFontBase.greekSheetEF
)
GameFontBase.sheetKey = shk
}

View File

@@ -1,6 +1,6 @@
package net.torvald.serialise
import net.torvald.terrarum.gamemap.GameMap
import net.torvald.terrarum.gamemap.GameWorld
import net.torvald.terrarum.Terrarum
import java.io.IOException
import java.nio.file.Files
@@ -29,14 +29,14 @@ object WriteGameMapData {
val path = Paths.get("${Terrarum.defaultSaveDir}" +
"/$saveDirectoryName/${WriteMeta.META_FILENAME}")
val tempPath = Files.createTempFile(path.toString(), "_temp")
val map = Terrarum.ingame.map
val map = Terrarum.ingame.world
// TODO gzip
// write binary
Files.write(tempPath, MAGIC)
Files.write(tempPath, byteArrayOf(GameMap.BITS))
Files.write(tempPath, byteArrayOf(GameMap.LAYERS))
Files.write(tempPath, byteArrayOf(GameWorld.BITS))
Files.write(tempPath, byteArrayOf(GameWorld.LAYERS))
Files.write(tempPath, byteArrayOf(BYTE_NULL))
Files.write(tempPath, byteArrayOf(BYTE_NULL))
Files.write(tempPath, toByteArray(map.width))

View File

@@ -58,9 +58,14 @@ All rights reserved.
---
Amazing ambient sound recordings in ```sound/ambient/klankbeeld-freesound```
Amazing ambient sound recordings:
Samples used: 173111, 183181, 185290, 195287, 240108, 326914, 337691, 347753
ambient_forest_01.ogg
ambient_meadow_01.ogg
ambient_windy_01.ogg
ambient_woods_01.ogg
crickets_01.ogg
crickets_02.ogg
Copyright (C) 2012, 2013, 2015, 2016 Klankbeeld
Sound from http://www.freesound.org/people/klankbeeld/

View File

@@ -1,6 +1,9 @@
package net.torvald.terrarum
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import net.torvald.terrarum.gamecontroller.Key
/**
* Created by minjaesong on 16-03-12.
@@ -15,6 +18,53 @@ object DefaultConfig {
jsonObject.addProperty("notificationshowuptime", 6500)
jsonObject.addProperty("multithread", true) // experimental!
// control-gamepad
jsonObject.addProperty("joypadkeyn", 4)
jsonObject.addProperty("joypadkeyw", 1)
jsonObject.addProperty("joypadkeys", 2)
jsonObject.addProperty("joypadkeye", 3) // logitech indices
jsonObject.addProperty("joypadlup", 4)
jsonObject.addProperty("joypadrup", 5)
jsonObject.addProperty("joypadldown", 6)
jsonObject.addProperty("joypadrdown", 7) // logitech indices
jsonObject.addProperty("joypadlstickx", 0)
jsonObject.addProperty("joypadlsticky", 1)
jsonObject.addProperty("joypadrstickx", 2)
jsonObject.addProperty("joypadrsticky", 3) // logitech indices
// control-keyboard (Java key index. This is what Minecraft also uses)
jsonObject.addProperty("keyup", Key.E)
jsonObject.addProperty("keyleft", Key.S)
jsonObject.addProperty("keydown", Key.D)
jsonObject.addProperty("keyright", Key.F)
jsonObject.addProperty("keymovementaux", Key.A) // movement-auxiliary, or hookshot
jsonObject.addProperty("keyinventory", Key.W)
jsonObject.addProperty("keyinteract", Key.R)
jsonObject.addProperty("keyclose", Key.C)
jsonObject.addProperty("keygamemenu", Key.TAB)
jsonObject.addProperty("keyquicksel", Key.CAPS_LOCK) // pie menu
val keyquickselalt = JsonArray(); keyquickselalt.add(Key.BACKSPACE); keyquickselalt.add(Key.L_COMMAND); keyquickselalt.add(Key.L_CONTROL)
// some pro typers assign CapsLock to Backspace, LControl, or LCommand (Mac). Honestly, Control (Command for mac) and CapsLock must swap their places!
jsonObject.add("keyquickselalt", keyquickselalt)
jsonObject.addProperty("keyjump", Key.SPACE)
val keyquickbars = JsonArray(); for (i in 2..11) keyquickbars.add(i) // NUM_1 to NUM_0
jsonObject.add("keyquickbars", keyquickbars)
return jsonObject
}
}
}
/*
Additional description goes here
*/

View File

@@ -1,6 +1,7 @@
package net.torvald.terrarum
import net.torvald.imagefont.GameFontBase
import net.torvald.terrarum.audio.AudioResourceLibrary
import net.torvald.terrarum.concurrent.ThreadPool
import net.torvald.terrarum.gameactors.*
import net.torvald.terrarum.console.Authenticator
@@ -9,7 +10,7 @@ import net.torvald.terrarum.gamecontroller.GameController
import net.torvald.terrarum.gamecontroller.Key
import net.torvald.terrarum.gamecontroller.KeyMap
import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.gamemap.GameMap
import net.torvald.terrarum.gamemap.GameWorld
import net.torvald.terrarum.gamemap.WorldTime
import net.torvald.terrarum.mapdrawer.LightmapRenderer
import net.torvald.terrarum.mapdrawer.MapCamera
@@ -22,6 +23,7 @@ import net.torvald.terrarum.ui.BasicDebugInfoWindow
import net.torvald.terrarum.ui.ConsoleWindow
import net.torvald.terrarum.ui.Notification
import net.torvald.terrarum.ui.UIHandler
import net.torvald.terrarum.weather.WeatherMixer
import org.lwjgl.opengl.GL11
import org.newdawn.slick.*
import org.newdawn.slick.fills.GradientFill
@@ -41,7 +43,7 @@ constructor() : BasicGameState() {
internal var game_mode = 0
lateinit var map: GameMap
lateinit var world: GameWorld
/**
* list of Actors that is sorted by Actors' referenceID
@@ -57,8 +59,8 @@ constructor() : BasicGameState() {
lateinit internal var player: Player
private var GRADIENT_IMAGE: Image? = null
private var skyBox: Rectangle? = null
//private var GRADIENT_IMAGE: Image? = null
//private var skyBox: Rectangle? = null
var screenZoom = 1.0f
val ZOOM_MAX = 2.0f
@@ -92,15 +94,11 @@ constructor() : BasicGameState() {
shaderBlurH = Shader.makeShader("./res/blurH.vrt", "./res/blur.frg")
shaderBlurV = Shader.makeShader("./res/blurV.vrt", "./res/blur.frg")
// init skybox
GRADIENT_IMAGE = Image("res/graphics/colourmap/sky_colour.png")
skyBox = Rectangle(0f, 0f, Terrarum.WIDTH.toFloat(), Terrarum.HEIGHT.toFloat())
// init map as chosen size
map = GameMap(8192, 2048)
world = GameWorld(8192, 2048)
// generate terrain for the map
MapGenerator.attachMap(map)
MapGenerator.attachMap(world)
MapGenerator.SEED = 0x51621D2
//mapgenerator.setSeed(new HQRNG().nextLong());
MapGenerator.generateMap()
@@ -132,6 +130,11 @@ constructor() : BasicGameState() {
// set smooth lighting as in config
KeyToggler.forceSet(KEY_LIGHTMAP_SMOOTH, Terrarum.getConfigBoolean("smoothlighting"))
// audio test
//AudioResourceLibrary.ambientsWoods[0].play()
}
override fun update(gc: GameContainer, sbg: StateBasedGame, delta: Int) {
@@ -139,8 +142,11 @@ constructor() : BasicGameState() {
setAppTitle()
map.updateWorldTime(delta)
map.globalLight = globalLightByTime
world.updateWorldTime(delta)
WeatherMixer.update(gc, delta)
world.globalLight = globalLightByTime.toInt()
GameController.processInput(gc.input)
@@ -258,30 +264,6 @@ constructor() : BasicGameState() {
}
}
private fun getGradientColour(row: Int, phase: Int) = GRADIENT_IMAGE!!.getColor(phase, row)
private fun getGradientColour(row: Int): Color {
val gradMapWidth = GRADIENT_IMAGE!!.width
val phase = Math.round(
map.worldTime.elapsedSeconds().toFloat() / WorldTime.DAY_LENGTH.toFloat() * gradMapWidth
)
//update in every INTERNAL_FRAME frames
return getGradientColour(row, phase)
}
/**
* @param time in seconds
*/
private fun getGradientColourByTime(row: Int, time: Int): Color {
val gradMapWidth = GRADIENT_IMAGE!!.width
val phase = Math.round(
time.toFloat() / WorldTime.DAY_LENGTH.toFloat() * gradMapWidth
)
return getGradientColour(row, phase)
}
override fun keyPressed(key: Int, c: Char) {
GameController.keyPressed(key, c)
}
@@ -320,13 +302,7 @@ constructor() : BasicGameState() {
override fun getID(): Int = Terrarum.SCENE_ID_GAME
private fun drawSkybox(g: Graphics) {
val skyColourFill = GradientFill(
0f, 0f, getGradientColour(0),
0f, Terrarum.HEIGHT.toFloat(), getGradientColour(1)
)
g.fill(skyBox, skyColourFill)
}
private fun drawSkybox(g: Graphics) = WeatherMixer.render(g)
/** Send message to notifier UI and toggle the UI as opened. */
fun sendNotification(msg: Array<String>) {
@@ -399,15 +375,7 @@ constructor() : BasicGameState() {
}
}
private val globalLightByTime: Int
get() = getGradientColour(2).getRGB24().rgb24ExpandToRgb30()
fun globalLightByTime(t: Int): Int = getGradientColourByTime(2, t).getRGB24().rgb24ExpandToRgb30()
fun Color.getRGB24(): Int = this.redByte.shl(16) or this.greenByte.shl(8) or this.blueByte
/** Remap 8-bit value (0.0-1.0) to 10-bit value (0.0-4.0) by prepending two bits of zero for each R, G and B. */
fun Int.rgb24ExpandToRgb30(): Int = (this and 0xff) or
(this and 0xff00).ushr(8).shl(10) or
(this and 0xff0000).ushr(16).shl(20)
private val globalLightByTime = WeatherMixer.globalLightNow
fun Double.sqr() = this * this
fun Int.sqr() = this * this

View File

@@ -0,0 +1,48 @@
package net.torvald.terrarum.audio
import org.lwjgl.openal.AL10
import org.newdawn.slick.openal.Audio
import org.newdawn.slick.openal.AudioImpl
import org.newdawn.slick.openal.MODSound
import java.util.*
/**
* Created by minjaesong on 16-07-08.
*/
object AudioMixer {
const val TRACK_COUNT = 32
const val TRACK_AMBIENT_ONE = 0
const val TRACK_AMBIENT_ONE_NEXT = 1
const val TRACK_AMBIENT_TWO = 2
const val TRACK_AMBIENT_TWO_NEXT = 3
const val TRACK_UI_ONE = 8
const val TRACK_UI_TWO = 9
const val TRACK_SFX_START = 16
const val TRACK_SFX_END = 31
val tracks = ArrayList<MixerTrack>(TRACK_COUNT)
init {
}
fun getAudio(track: Int) = tracks[track]
/**
* Queue an SFX to any empty SFX track and play it.
*/
fun queueSfx(audio: Audio) {
}
fun update() {
}
class MixerTrack(val audio: Audio, var volume: Float, var pan: Float) {
}
}

View File

@@ -0,0 +1,31 @@
package net.torvald.terrarum.audio
import org.newdawn.slick.openal.Audio
import org.newdawn.slick.openal.AudioLoader
import java.io.FileInputStream
import java.util.*
/**
* Created by minjaesong on 16-07-08.
*/
object AudioResourceLibrary {
val ambientsForest = ArrayList<Audio>()
val ambientsMeadow = ArrayList<Audio>()
val ambientsWindy = ArrayList<Audio>()
val ambientsWoods = ArrayList<Audio>()
val crickets = ArrayList<Audio>()
init {
ambientsForest.add(AudioLoader.getAudio("ogg", FileInputStream("./res/sounds/ambient/ambient_forest_01.ogg")))
ambientsMeadow.add(AudioLoader.getAudio("ogg", FileInputStream("./res/sounds/ambient/ambient_meadow_01.ogg")))
ambientsWindy.add(AudioLoader.getAudio("ogg", FileInputStream("./res/sounds/ambient/ambient_windy_01.ogg")))
ambientsWoods.add(AudioLoader.getAudio("ogg", FileInputStream("./res/sounds/ambient/ambient_woods_01.ogg")))
crickets.add(AudioLoader.getAudio("ogg", FileInputStream("./res/sounds/ambient/crickets_01.ogg")))
crickets.add(AudioLoader.getAudio("ogg", FileInputStream("./res/sounds/ambient/crickets_02.ogg")))
}
}

View File

@@ -1,8 +1,7 @@
package net.torvald.terrarum.console
import net.torvald.terrarum.StateInGame
import net.torvald.imagefont.GameFontBase
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.ui.ConsoleWindow
import java.util.Formatter
@@ -10,6 +9,9 @@ import java.util.Formatter
* Created by minjaesong on 16-01-16.
*/
class CodexEdictis : ConsoleCommand {
val ccW = GameFontBase.colToCode["o"]
override fun execute(args: Array<String>) {
if (args.size == 1) {
printList()
@@ -23,7 +25,7 @@ class CodexEdictis : ConsoleCommand {
val sb = StringBuilder()
val formatter = Formatter(sb)
Echo().execute("Codex: " + formatter.format(Lang.get("DEV_MESSAGE_CONSOLE_COMMAND_UNKNOWN"), args[1]).toString())
Echo().execute("Codex: " + formatter.format(Lang["DEV_MESSAGE_CONSOLE_COMMAND_UNKNOWN"], args[1]).toString())
}
}
@@ -38,8 +40,11 @@ class CodexEdictis : ConsoleCommand {
private fun printList() {
val echo = Echo()
echo.execute(Lang.get("DEV_MESSAGE_CONSOLE_AVAILABLE_COMMANDS"))
CommandDict.dict.keys.forEach { s -> echo.execute("" + s) }
echo.execute(Lang["DEV_MESSAGE_CONSOLE_AVAILABLE_COMMANDS"])
CommandDict.dict.forEach { name, cmd ->
echo.execute("$ccW" + name)
cmd.printUsage()
}
}
}

View File

@@ -42,7 +42,8 @@ object CommandDict {
// Test codes
Pair("bulletintest", SetBulletin()),
Pair("gsontest", GsonTest()),
Pair("tips", PrintRandomTips())
Pair("tips", PrintRandomTips()),
Pair("langtest", LangTest())
)
fun getCommand(commandName: String): ConsoleCommand {

View File

@@ -5,6 +5,12 @@ package net.torvald.terrarum.console
*/
interface ConsoleCommand {
/**
* Args 0: command given
* Args 1: first argument
*
* e.g. in ```setav mass 74```, zeroth args will be ```setav```.
*/
@Throws(Exception::class)
fun execute(args: Array<String>)

View File

@@ -22,10 +22,10 @@ class ExportMap : ConsoleCommand {
if (args.size == 2) {
buildColorTable()
var mapData = ByteArray(Terrarum.ingame.map.width * Terrarum.ingame.map.height * 3)
var mapData = ByteArray(Terrarum.ingame.world.width * Terrarum.ingame.world.height * 3)
var mapDataPointer = 0
for (tile in Terrarum.ingame.map.terrainIterator()) {
for (tile in Terrarum.ingame.world.terrainIterator()) {
val colArray = (colorTable as Map<Int, Col4096>)
.getOrElse(tile, { Col4096(0xFFF) }).toByteArray()
@@ -44,7 +44,7 @@ class ExportMap : ConsoleCommand {
try {
RasterWriter.writePNG_RGB(
Terrarum.ingame.map.width, Terrarum.ingame.map.height, mapData, dir + args[1] + ".png")
Terrarum.ingame.world.width, Terrarum.ingame.world.height, mapData, dir + args[1] + ".png")
Echo().execute("ExportMap: exported to " + args[1] + ".png")
}

View File

@@ -8,7 +8,7 @@ import net.torvald.terrarum.Terrarum
class GetTime : ConsoleCommand {
override fun execute(args: Array<String>) {
val echo = Echo()
val worldTime = Terrarum.ingame.map.worldTime
val worldTime = Terrarum.ingame.world.time
echo.execute("Year ${worldTime.years}, Month ${worldTime.months}, " +
"Day ${worldTime.days} (${worldTime.getDayNameShort()}), " +
"${worldTime.getFormattedTime()}"

View File

@@ -0,0 +1,19 @@
package net.torvald.terrarum.console
import net.torvald.terrarum.langpack.Lang
/**
* Created by minjaesong on 16-07-11.
*/
class LangTest : ConsoleCommand {
override fun printUsage() {
Echo().execute("Prints out string in the current lang pack by STRING_ID provided")
}
override fun execute(args: Array<String>) {
if (args.size < 2)
printUsage()
else
Echo().execute(Lang[args[1].toUpperCase()])
}
}

View File

@@ -13,7 +13,7 @@ class Seed : ConsoleCommand {
// tsalagi
override fun execute(args: Array<String>) {
Echo().execute("${ccY}Map$ccW: $ccG${Terrarum.ingame.map.generatorSeed}")
Echo().execute("Map$ccW: $ccG${Terrarum.ingame.world.generatorSeed}")
// TODO display randomiser seed
}

View File

@@ -19,8 +19,8 @@ internal class SetAV : ConsoleCommand {
val echo = Echo()
echo.execute("${ccW}Set actor value of specific target to desired value.")
echo.execute("${ccW}Usage: ${ccY}setav ${ccG}(id) <av> <val>")
echo.execute("${ccW}blank ID for player")
echo.execute("${ccR}Contaminated (double -> string) ActorValue will crash the game,")
echo.execute("${ccW}blank ID for player. Data type will be inferred automatically.")
echo.execute("${ccR}Contaminated (e.g. double -> string) ActorValue will crash the game,")
echo.execute("${ccR}so make sure it will not happen before you issue the command!")
echo.execute("${ccW}Use ${ccG}__true ${ccW}and ${ccG}__false ${ccW}for boolean value.")
}

View File

@@ -15,7 +15,7 @@ class SetGlobalLightLevel : ConsoleCommand {
val b = args[3].toInt()
val GL = LightmapRenderer.constructRGBFromInt(r, g, b)
Terrarum.ingame.map.globalLight = GL
Terrarum.ingame.world.globalLight = GL
}
catch (e: NumberFormatException) {
Echo().execute("Wrong number input.")
@@ -33,7 +33,7 @@ class SetGlobalLightLevel : ConsoleCommand {
Echo().execute("Range: 0-" + (LightmapRenderer.COLOUR_RANGE_SIZE - 1))
}
else {
Terrarum.ingame.map.globalLight = GL
Terrarum.ingame.world.globalLight = GL
}
}
catch (e: NumberFormatException) {

View File

@@ -11,10 +11,10 @@ class SetTime : ConsoleCommand {
if (args.size == 2) {
val timeToSet = WorldTime.parseTime(args[1])
Terrarum.ingame.map.worldTime.setTime(timeToSet)
Terrarum.ingame.world.time.setTime(timeToSet)
Echo().execute("Set time to ${Terrarum.ingame.map.worldTime.elapsedSeconds()} " +
"(${Terrarum.ingame.map.worldTime.hours}h${formatMin(Terrarum.ingame.map.worldTime.minutes)})")
Echo().execute("Set time to ${Terrarum.ingame.world.time.elapsedSeconds()} " +
"(${Terrarum.ingame.world.time.hours}h${formatMin(Terrarum.ingame.world.time.minutes)})")
}
else {
printUsage()

View File

@@ -14,11 +14,11 @@ class SetTimeDelta : ConsoleCommand {
if (args[1].toInt() > HARD_LIMIT)
Error().execute("Delta too large -- acceptable delta is 0-60.")
Terrarum.ingame.map.worldTime.setTimeDelta(args[1].toInt())
if (Terrarum.ingame.map.worldTime.timeDelta == 0)
Terrarum.ingame.world.time.setTimeDelta(args[1].toInt())
if (Terrarum.ingame.world.time.timeDelta == 0)
Echo().execute("時間よ止まれ!ザ・ワルド!!")
else
Echo().execute("Set time delta to ${Terrarum.ingame.map.worldTime.timeDelta}")
Echo().execute("Set time delta to ${Terrarum.ingame.world.time.timeDelta}")
}
else {
printUsage()

View File

@@ -6,5 +6,5 @@ import net.torvald.terrarum.gameactors.ai.ActorAI
* Created by minjaesong on 16-03-14.
*/
interface AIControlled {
fun attachAI(ai: ActorAI)
var actorAI: ActorAI
}

View File

@@ -1,6 +1,8 @@
package net.torvald.terrarum.gameactors
/**
* See [res/raw/Creature_raw_doc.md] for information about raw.
*
* Created by minjaesong on 16-04-02.
*/
object AVKey {

View File

@@ -1,7 +1,7 @@
package net.torvald.terrarum.gameactors
import net.torvald.terrarum.*
import net.torvald.terrarum.gamemap.GameMap
import net.torvald.terrarum.gamemap.GameWorld
import net.torvald.terrarum.mapdrawer.MapDrawer
import net.torvald.terrarum.tileproperties.TilePropCodex
import net.torvald.spriteanimation.SpriteAnimation
@@ -24,7 +24,7 @@ open class ActorWithBody : Actor(), Visible {
@Transient var sprite: SpriteAnimation? = null
@Transient var spriteGlow: SpriteAnimation? = null
@Transient private val map: GameMap = Terrarum.ingame.map
@Transient private val world: GameWorld = Terrarum.ingame.world
var hitboxTranslateX: Double = 0.0// relative to spritePosX
var hitboxTranslateY: Double = 0.0// relative to spritePosY
@@ -103,7 +103,13 @@ open class ActorWithBody : Actor(), Visible {
set(value) { elasticity = 1.0 - value }
get() = 1.0 - elasticity
private var density = 1000.0
var density = 1000.0
set(value) {
if (value < 0)
throw IllegalArgumentException("[ActorWithBody] $value: density cannot be negative.")
field = value
}
/**
* Flags and Properties
@@ -145,7 +151,7 @@ open class ActorWithBody : Actor(), Visible {
* s^2 = 1/FPS = 1/60 if FPS is targeted to 60
* meter to pixel : 24/FPS
*/
@Transient private val gravitation: Vector2 = map.gravitation
@Transient private val gravitation: Vector2 = world.gravitation
@Transient val DRAG_COEFF_DEFAULT = 1.2
/** Drag coefficient. Parachutes have much higher value than bare body (1.2) */
private var DRAG_COEFF: Double
@@ -361,9 +367,15 @@ open class ActorWithBody : Actor(), Visible {
}
}
/**
* FIXME the culprit!
* (5566 -> no colliiding but player does not "sink")
* (5567 -> colliding)
* How to fix:
*/
private fun applyNormalForce() {
if (!isNoCollideWorld) {
// axis Y
// axis Y. Use operand >=
if (moveDelta.y >= 0.0) { // was moving downward?
if (isTouchingSide(nextHitbox, COLLIDING_BOTTOM)) { // actor hit something on its bottom
hitAndReflectY()
@@ -493,14 +505,14 @@ open class ActorWithBody : Actor(), Visible {
}
}
val txStart = x1.div(TSIZE).roundInt()
val txEnd = x2.div(TSIZE).roundInt()
val tyStart = y1.div(TSIZE).roundInt()
val tyEnd = y2.div(TSIZE).roundInt()
val txStart = x1.div(TSIZE).floorInt()
val txEnd = x2.div(TSIZE).floorInt()
val tyStart = y1.div(TSIZE).floorInt()
val tyEnd = y2.div(TSIZE).floorInt()
for (y in tyStart..tyEnd) {
for (x in txStart..txEnd) {
val tile = map.getTileFromTerrain(x, y)
val tile = world.getTileFromTerrain(x, y)
if (TilePropCodex.getProp(tile).isSolid)
return true
}
@@ -537,14 +549,14 @@ open class ActorWithBody : Actor(), Visible {
}
else throw IllegalArgumentException()
val txStart = x1.div(TSIZE).roundInt()
val txEnd = x2.div(TSIZE).roundInt()
val tyStart = y1.div(TSIZE).roundInt()
val tyEnd = y2.div(TSIZE).roundInt()
val txStart = x1.plus(1.0).div(TSIZE).floorInt()
val txEnd = x2.plus(1.0).div(TSIZE).floorInt()
val tyStart = y1.plus(1.0).div(TSIZE).floorInt()
val tyEnd = y2.plus(1.0).div(TSIZE).floorInt()
for (y in tyStart..tyEnd) {
for (x in txStart..txEnd) {
val tile = map.getTileFromTerrain(x, y)
val tile = world.getTileFromTerrain(x, y)
if (TilePropCodex.getProp(tile).isSolid)
return true
}
@@ -589,7 +601,7 @@ open class ActorWithBody : Actor(), Visible {
for (y in tyStart..tyEnd) {
for (x in txStart..txEnd) {
val tile = map.getTileFromTerrain(x, y)
val tile = world.getTileFromTerrain(x, y)
if (TilePropCodex.getProp(tile).isSolid)
return true
}
@@ -629,7 +641,7 @@ open class ActorWithBody : Actor(), Visible {
}
// evaluate
if (TilePropCodex.getProp(map.getTileFromTerrain(tileX, tileY)).isFluid) {
if (TilePropCodex.getProp(world.getTileFromTerrain(tileX, tileY)).isFluid) {
contactAreaCounter += 1
}
}
@@ -727,7 +739,7 @@ open class ActorWithBody : Actor(), Visible {
val tilePosXEnd = (hitbox.hitboxEnd.x / TSIZE).roundInt()
val tilePosY = (hitbox.pointedY.plus(1) / TSIZE).roundInt()
for (x in tilePosXStart..tilePosXEnd) {
val tile = map.getTileFromTerrain(x, tilePosY)
val tile = world.getTileFromTerrain(x, tilePosY)
val thisFriction = TilePropCodex.getProp(tile).friction
if (thisFriction > friction) friction = thisFriction
@@ -751,7 +763,7 @@ open class ActorWithBody : Actor(), Visible {
val tilePosYEnd = (hitbox.hitboxEnd.y / TSIZE).roundInt()
for (y in tilePosXStart..tilePosYEnd) {
for (x in tilePosXStart..tilePosXEnd) {
val tile = map.getTileFromTerrain(x, y)
val tile = world.getTileFromTerrain(x, y)
val prop = TilePropCodex.getProp(tile)
if (prop.isFluid && prop.density > density)
@@ -776,7 +788,7 @@ open class ActorWithBody : Actor(), Visible {
val tilePosYEnd = (nextHitbox.hitboxEnd.y / TSIZE).roundInt()
for (y in tilePosYStart..tilePosYEnd) {
for (x in tilePosXStart..tilePosXEnd) {
val tile = map.getTileFromTerrain(x, y)
val tile = world.getTileFromTerrain(x, y)
val thisFluidDensity = TilePropCodex.getProp(tile).density
if (thisFluidDensity > density) density = thisFluidDensity
@@ -849,8 +861,8 @@ open class ActorWithBody : Actor(), Visible {
private fun clampW(x: Double): Double =
if (x < TSIZE + nextHitbox.width / 2) {
TSIZE + nextHitbox.width / 2
} else if (x >= (map.width * TSIZE).toDouble() - TSIZE.toDouble() - nextHitbox.width / 2) {
(map.width * TSIZE).toDouble() - 1.0 - TSIZE.toDouble() - nextHitbox.width / 2
} else if (x >= (world.width * TSIZE).toDouble() - TSIZE.toDouble() - nextHitbox.width / 2) {
(world.width * TSIZE).toDouble() - 1.0 - TSIZE.toDouble() - nextHitbox.width / 2
} else {
x
}
@@ -858,40 +870,22 @@ open class ActorWithBody : Actor(), Visible {
private fun clampH(y: Double): Double =
if (y < TSIZE + nextHitbox.height) {
TSIZE + nextHitbox.height
} else if (y >= (map.height * TSIZE).toDouble() - TSIZE.toDouble() - nextHitbox.height) {
(map.height * TSIZE).toDouble() - 1.0 - TSIZE.toDouble() - nextHitbox.height
} else if (y >= (world.height * TSIZE).toDouble() - TSIZE.toDouble() - nextHitbox.height) {
(world.height * TSIZE).toDouble() - 1.0 - TSIZE.toDouble() - nextHitbox.height
} else {
y
}
private fun clampWtile(x: Int): Int =
if (x < 0) {
0
} else if (x >= map.width) {
map.width - 1
} else {
x
}
if (x < 0) 0 else if (x >= world.width) world.width - 1 else x
private fun clampHtile(x: Int): Int =
if (x < 0) {
0
} else if (x >= map.height) {
map.height - 1
} else {
x
}
if (x < 0) 0 else if (x >= world.height) world.height - 1 else x
private val isPlayerNoClip: Boolean
get() = this is Player && this.isNoClip()
fun setDensity(density: Int) {
if (density < 0)
throw IllegalArgumentException("[ActorWithBody] $density: density cannot be negative.")
this.density = density.toDouble()
}
private val AUTO_CLIMB_RATE: Int
get() = Math.min(TSIZE / 8 * Math.sqrt(scale), TSIZE.toDouble()).toInt()
@@ -907,6 +901,17 @@ open class ActorWithBody : Actor(), Visible {
if (this > 0 && this > limit) limit
else if (this < 0 && this < -limit) -limit
else this
fun Double.floorSpecial(): Int {
val threshold = 1.1 / TSIZE.toDouble()
// the idea is 321.0625 would rounded to 321, 320.9375 would rounded to 321,
// and regular flooring for otherwise.
if (this % TSIZE.toDouble() <= threshold) // case: 321.0625
return this.floorInt()
else if (1.0 - this.mod(TSIZE.toDouble()) <= threshold) // case: 320.9375
return this.floorInt() + 1
else
return this.floorInt()
}
private fun assertInit() {
// errors
@@ -929,8 +934,8 @@ open class ActorWithBody : Actor(), Visible {
private fun div16TruncateToMapWidth(x: Int): Int {
if (x < 0)
return 0
else if (x >= Terrarum.ingame.map.width shl 4)
return Terrarum.ingame.map.width - 1
else if (x >= Terrarum.ingame.world.width shl 4)
return Terrarum.ingame.world.width - 1
else
return x and 0x7FFFFFFF shr 4
}
@@ -938,8 +943,8 @@ open class ActorWithBody : Actor(), Visible {
private fun div16TruncateToMapHeight(y: Int): Int {
if (y < 0)
return 0
else if (y >= Terrarum.ingame.map.height shl 4)
return Terrarum.ingame.map.height - 1
else if (y >= Terrarum.ingame.world.height shl 4)
return Terrarum.ingame.world.height - 1
else
return y and 0x7FFFFFFF shr 4
}

View File

@@ -7,8 +7,6 @@ import net.torvald.terrarum.gameitem.InventoryItem
*/
interface CanBeAnItem {
fun attachItemData()
fun getItemWeight(): Double
fun stopUpdateAndDraw()

View File

@@ -19,7 +19,7 @@ class FixturesTikiTorch : FixturesBase(), Luminous {
init {
isVisible = true
super.setDensity(1200)
density = 1200.0
setHitboxDimension(10, 24, 0, 0)

View File

@@ -11,9 +11,9 @@ interface LandHolder {
* Absolute tile index. index(x, y) = y * map.width + x
* The arraylist will be saved in JSON format with GSON.
*/
var houseDesignation: ArrayList<Int>?
fun addHouseTile(x: Int, y: Int);
fun removeHouseTile(x: Int, y: Int);
fun clearHouseDesignation();
var houseDesignation: ArrayList<Long>?
fun addHouseTile(x: Int, y: Int)
fun removeHouseTile(x: Int, y: Int)
fun clearHouseDesignation()
}

View File

@@ -1,10 +1,9 @@
package net.torvald.terrarum.gameactors
import net.torvald.random.HQRNG
import net.torvald.terrarum.gameactors.ai.ActorAI
import net.torvald.terrarum.gameactors.faction.Faction
import net.torvald.terrarum.gameitem.InventoryItem
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.realestate.RealEstateUtility.getAbsoluteTileNumber
import org.newdawn.slick.GameContainer
import java.util.*
@@ -14,19 +13,27 @@ import java.util.*
open class NPCIntelligentBase : ActorWithBody()
, AIControlled, Pocketed, CanBeAnItem, Factionable, LandHolder {
override var actorAI: ActorAI = object : ActorAI {
// TODO fully establish ActorAI so that I can implement AI here
}
override var inventory: ActorInventory = ActorInventory()
override var faction: HashSet<Faction> = HashSet()
override var houseDesignation: ArrayList<Long>? = null
// we're having InventoryItem data so that this class could be somewhat universal
override var itemData: InventoryItem = object : InventoryItem {
override var itemID = HQRNG().nextInt()
override var itemID = referenceID
override var mass: Double
get() = actorValue.getAsDouble("mass")!!
get() = actorValue.getAsDouble(AVKey.BASEMASS)!!
set(value) {
actorValue.set("mass", value)
actorValue[AVKey.BASEMASS] = value
}
override var scale: Double
get() = actorValue.getAsDouble("scale")!!
get() = actorValue.getAsDouble(AVKey.SCALE)!!
set(value) {
actorValue.set("scale", value)
actorValue[AVKey.SCALE] = value
}
override fun effectWhileInPocket(gc: GameContainer, delta_t: Int) {
@@ -38,52 +45,32 @@ open class NPCIntelligentBase : ActorWithBody()
}
override fun primaryUse(gc: GameContainer, delta_t: Int) {
// TODO do not allow primary_use
}
override fun secondaryUse(gc: GameContainer, delta_t: Int) {
// TODO place this Actor to the world
}
override fun effectWhenThrownAway(gc: GameContainer, delta_t: Int) {
override fun effectWhenThrown(gc: GameContainer, delta_t: Int) {
}
}
@Transient private var ai: ActorAI? = null
override var inventory: ActorInventory = ActorInventory()
private val factionSet = HashSet<Faction>()
override var referenceID: Int = HQRNG().nextInt()
override var faction: HashSet<Faction> = HashSet()
override var houseDesignation: ArrayList<Int>? = null
/**
* Absolute tile index. index(x, y) = y * map.width + x
* The arraylist will be saved in JSON format with GSON.
*/
private var houseTiles = ArrayList<Int>()
override fun attachItemData() {
}
override fun getItemWeight(): Double {
return mass
}
override fun addHouseTile(x: Int, y: Int) {
houseTiles.add(Terrarum.ingame.map.width * y + x)
if (houseDesignation != null) houseDesignation!!.add(getAbsoluteTileNumber(x, y))
}
override fun removeHouseTile(x: Int, y: Int) {
houseTiles.remove(Terrarum.ingame.map.width * y + x)
if (houseDesignation != null) houseDesignation!!.remove(getAbsoluteTileNumber(x, y))
}
override fun clearHouseDesignation() {
houseTiles.clear()
if (houseDesignation != null) houseDesignation!!.clear()
}
override fun stopUpdateAndDraw() {
@@ -96,7 +83,5 @@ open class NPCIntelligentBase : ActorWithBody()
isVisible = true
}
override fun attachAI(ai: ActorAI) {
this.ai = ai
}
}

View File

@@ -15,7 +15,8 @@ class PhysTestBall : ActorWithBody() {
init {
setHitboxDimension(16, 16, 0, 0)
isVisible = true
actorValue[AVKey.BASEMASS] = 10.0
mass = 10.0
density = 200.0
color = RoguelikeRandomiser.composeColourFrom(RoguelikeRandomiser.POTION_PRIMARY_COLSET)
}

View File

@@ -56,7 +56,7 @@ class Player : ActorWithBody(), Controllable, Pocketed, Factionable, Luminous, L
@Transient private val TSIZE = MapDrawer.TILE_SIZE
@Transient private val BASE_DENSITY = 1020
@Transient private val BASE_DENSITY = 980.0
/** Must be set by PlayerFactory */
override var inventory: ActorInventory = ActorInventory()
@@ -64,7 +64,7 @@ class Player : ActorWithBody(), Controllable, Pocketed, Factionable, Luminous, L
/** Must be set by PlayerFactory */
override var faction: HashSet<Faction> = HashSet()
override var houseDesignation: ArrayList<Int>? = null
override var houseDesignation: ArrayList<Long>? = null
override var luminosity: Int
get() = actorValue.getAsInt(AVKey.LUMINOSITY) ?: 0
@@ -92,7 +92,7 @@ class Player : ActorWithBody(), Controllable, Pocketed, Factionable, Luminous, L
init {
isVisible = true
referenceID = PLAYER_REF_ID // forcibly set ID
super.setDensity(BASE_DENSITY)
density = BASE_DENSITY
collisionType = KINEMATIC
}

View File

@@ -42,7 +42,7 @@ object GameController {
if (input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) {
// test tile remove
try {
Terrarum.ingame.map.setTileTerrain(mouseTileX, mouseTileY, TileNameCode.AIR)
Terrarum.ingame.world.setTileTerrain(mouseTileX, mouseTileY, TileNameCode.AIR)
// terrarum.game.map.setTileWall(mouseTileX, mouseTileY, TileNameCode.AIR);
}
catch (e: ArrayIndexOutOfBoundsException) {
@@ -52,7 +52,7 @@ object GameController {
else if (input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON)) {
// test tile place
try {
Terrarum.ingame.map.setTileTerrain(mouseTileX, mouseTileY, Terrarum.ingame.player.actorValue.getAsInt("selectedtile")!!)
Terrarum.ingame.world.setTileTerrain(mouseTileX, mouseTileY, Terrarum.ingame.player.actorValue.getAsInt("selectedtile")!!)
}
catch (e: ArrayIndexOutOfBoundsException) {
}

View File

@@ -6,11 +6,16 @@ package net.torvald.terrarum.gamecontroller
object Key {
val RET = 28
val BKSP = 14
val BACKSPACE = 14
val GRAVE = 41
val TAB = 15
val ESCAPE = 1
val SPACE = 57
val CAPS_LOCK = 58
val L_CONTROL = 29
val L_COMMAND = 219 // Mac
val DELETE = 211
val L_SHIFT = 42
val R_SHIFT = 54
@@ -46,12 +51,12 @@ object Key {
val NUM_9 = 10
val NUM_0 = 11
// JInput is QWERTY-based
val Q = 16
val W = 17
val E = 18
val R = 19
val T = 20
val Y = 21
val U = 22
val I = 23
@@ -63,7 +68,6 @@ object Key {
val D = 32
val F = 33
val G = 34
val H = 35
val J = 36
val K = 37
@@ -75,7 +79,6 @@ object Key {
val C = 46
val V = 47
val B = 48
val N = 49
val M = 50

View File

@@ -25,7 +25,7 @@ interface InventoryItem {
var scale: Double
/**
* Effects applied while in pocket
* Effects applied continuously while in pocket
* @param gc
* *
* @param delta_t
@@ -41,7 +41,7 @@ interface InventoryItem {
fun effectWhenPickedUp(gc: GameContainer, delta_t: Int)
/**
* Effects applied while primary button (usually left mouse button) is down
* Effects applied (continuously or not) while primary button (usually left mouse button) is down
* @param gc
* *
* @param delta_t
@@ -49,7 +49,7 @@ interface InventoryItem {
fun primaryUse(gc: GameContainer, delta_t: Int)
/**
* Effects applied while secondary button (usually right mouse button) is down
* Effects applied (continuously or not) while secondary button (usually right mouse button) is down
* @param gc
* *
* @param delta_t
@@ -62,5 +62,5 @@ interface InventoryItem {
* *
* @param delta_t
*/
fun effectWhenThrownAway(gc: GameContainer, delta_t: Int)
fun effectWhenThrown(gc: GameContainer, delta_t: Int)
}

View File

@@ -33,7 +33,7 @@ class TileAsItem(tileNum: Int) : InventoryItem {
throw UnsupportedOperationException()
}
override fun effectWhenThrownAway(gc: GameContainer, delta_t: Int) {
override fun effectWhenThrown(gc: GameContainer, delta_t: Int) {
throw UnsupportedOperationException()
}
}

View File

@@ -4,7 +4,7 @@ package net.torvald.terrarum.gamemap
import org.dyn4j.geometry.Vector2
import org.newdawn.slick.SlickException
class GameMap
class GameWorld
/**
* @param width
* *
@@ -36,7 +36,7 @@ constructor(//properties
var gravitation: Vector2 = Vector2(0.0, 9.8)
/** RGB in Integer */
var globalLight: Int = 0
val worldTime: WorldTime
val time: WorldTime
var generatorSeed: Long = 0
@@ -50,8 +50,7 @@ constructor(//properties
terrainDamage = PairedMapLayer(width, height)
wallDamage = PairedMapLayer(width, height)
globalLight = 0.toChar().toInt()
worldTime = WorldTime()
time = WorldTime()
}
/**
@@ -169,7 +168,7 @@ constructor(//properties
}
fun updateWorldTime(delta: Int) {
worldTime.update(delta)
time.update(delta)
}
fun terrainIterator(): Iterator<Int> {

View File

@@ -1,8 +1,10 @@
package net.torvald.terrarum.itemproperties
import net.torvald.random.HQRNG
import net.torvald.terrarum.gameactors.CanBeAnItem
import net.torvald.terrarum.gameitem.InventoryItem
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gamemap.GameWorld
import org.newdawn.slick.GameContainer
import java.util.*
@@ -20,6 +22,7 @@ object ItemPropCodex {
private lateinit var itemCodex: Array<InventoryItem>
const val ITEM_UNIQUE_MAX = 32768
val TILE_MAX = GameWorld.TILES_SUPPORTED
init {
itemCodex = arrayOf<InventoryItem>()

View File

@@ -20,7 +20,8 @@ object Lang {
*
* HashMap<"$key_$language", Value>
*/
private var langpack: HashMap<String, String>
var langpack: HashMap<String, String>
private set
private val FALLBACK_LANG_CODE = "en"
private val HANGUL_SYL_START = 0xAC00

View File

@@ -0,0 +1,195 @@
package net.torvald.terrarum.mapdrawer
import com.jme3.math.FastMath
import org.newdawn.slick.Color
/**
* Created by minjaesong on 16-07-08.
*/
class Light10B {
private var data = 0
constructor(r: Int, g: Int, b: Int) {
data = constructRGBFromInt(r, g, b)
}
constructor(r: Float, g: Float, b: Float) {
if (r < 0 || r > 1.0f) throw IllegalArgumentException("Red: out of range ($r)")
if (g < 0 || g > 1.0f) throw IllegalArgumentException("Green: out of range ($g)")
if (b < 0 || b > 1.0f) throw IllegalArgumentException("Blue: out of range ($b)")
val intR = (r * CHANNEL_MAX).floor()
val intG = (g * CHANNEL_MAX).floor()
val intB = (b * CHANNEL_MAX).floor()
data = constructRGBFromInt(intR, intG, intB)
}
constructor(raw: Int) {
data = raw
}
constructor(color: Color) {
data = constructRGBFromInt(color.red, color.green, color.blue)
}
/**
* Assigners
*/
fun fromRGB(r: Int, g: Int, b: Int): Light10B {
data = constructRGBFromInt(r, g, b)
return this
}
fun fromInt(raw: Int): Light10B {
data = raw
return this
}
fun fromSlickColor(color: Color): Light10B {
data = constructRGBFromInt(color.red, color.green, color.blue)
return this
}
fun toInt(): Int = data
fun constructRGBFromInt(r: Int, g: Int, b: Int): Int {
if (r !in 0..CHANNEL_MAX) throw IllegalArgumentException("Red: out of range ($r)")
if (g !in 0..CHANNEL_MAX) throw IllegalArgumentException("Green: out of range ($g)")
if (b !in 0..CHANNEL_MAX) throw IllegalArgumentException("Blue: out of range ($b)")
return (r * STEPS_2 + g * STEPS + b)
}
val STEPS = 1024
val STEPS_2 = STEPS * STEPS
val CHANNEL_MAX = STEPS - 1
val CHANNEL_MAX_FLOAT = CHANNEL_MAX.toFloat()
val CHANNEL_MAX_DECIMAL = 4f
val COLOUR_RANGE_SIZE = STEPS * STEPS_2
override fun toString() = "10BitCol:$data"
fun rawR() = data / STEPS_2
fun rawG() = data % STEPS_2 / STEPS
fun rawB() = data % STEPS
fun r(): Float = this.rawR() / CHANNEL_MAX_FLOAT
fun g(): Float = this.rawG() / CHANNEL_MAX_FLOAT
fun b(): Float = this.rawB() / CHANNEL_MAX_FLOAT
fun Float.floor() = FastMath.floor(this)
private fun Float.clampChannel() = if (this < 0) 0f else if (this > CHANNEL_MAX_DECIMAL) CHANNEL_MAX_DECIMAL else this
private fun Int.clampChannel() = if (this < 0) 0 else if (this > CHANNEL_MAX) CHANNEL_MAX else this
operator fun plus(other: Light10B) =
Light10B(
rawR().plus(other.rawR()).clampChannel(),
rawG().plus(other.rawG()).clampChannel(),
rawB().plus(other.rawB()).clampChannel()
)
operator fun minus(other: Light10B) =
Light10B(
rawR().minus(other.rawR()).clampChannel(),
rawG().minus(other.rawG()).clampChannel(),
rawB().minus(other.rawB()).clampChannel()
)
operator fun times(other: Light10B) =
Light10B(
r().times(other.r()).clampChannel(),
g().times(other.g()).clampChannel(),
b().times(other.b()).clampChannel()
)
infix fun darken(other: Light10B): Light10B {
if (other.toInt() < 0 || other.toInt() >= COLOUR_RANGE_SIZE)
throw IllegalArgumentException("darken: out of range ($other)")
val r = this.r() * (1f - other.r() * 6) // 6: Arbitrary value
val g = this.g() * (1f - other.g() * 6) // TODO gamma correction?
val b = this.b() * (1f - other.b() * 6)
return Light10B(r.clampChannel(), g.clampChannel(), b.clampChannel())
}
infix fun darken(darken: Int): Light10B {
if (darken < 0 || darken > CHANNEL_MAX)
throw IllegalArgumentException("darken: out of range ($darken)")
val darkenColoured = constructRGBFromInt(darken, darken, darken)
return (this darken darkenColoured)
}
infix fun brighten(other: Light10B): Light10B {
if (other.toInt() < 0 || other.toInt() >= COLOUR_RANGE_SIZE)
throw IllegalArgumentException("brighten: out of range ($other)")
val r = this.r() * (1f + other.r() * 6) // 6: Arbitrary value
val g = this.g() * (1f + other.g() * 6) // TODO gamma correction?
val b = this.b() * (1f + other.b() * 6)
return Light10B(r.clampChannel(), g.clampChannel(), b.clampChannel())
}
/**
* Darken or brighten colour by 'brighten' argument
*
* @param data Raw channel value (0-255) per channel
* @param brighten (-1.0 - 1.0) negative means darkening
* @return processed colour
*/
fun alterBrightnessUniform(data: Light10B, brighten: Float): Light10B {
val modifier = if (brighten < 0)
Light10B(-brighten, -brighten, -brighten)
else
Light10B(brighten, brighten, brighten)
return if (brighten < 0)
data darken modifier
else
data brighten modifier
}
/** Get each channel from two RGB values, return new RGB that has max value of each channel
* @param rgb
* @param rgb2
* @return
*/
infix fun maxBlend(other: Light10B): Light10B {
val r1 = this.rawR()
val r2 = other.rawR()
val newR = if (r1 > r2) r1 else r2
val g1 = this.rawG()
val g2 = other.rawG()
val newG = if (g1 > g2) g1 else g2
val b1 = this.rawB()
val b2 = other.rawB()
val newB = if (b1 > b2) b1 else b2
return Light10B(newR, newG, newB)
}
infix fun screenBlend(other: Light10B): Light10B {
val r1 = this.r()
val r2 = other.r()
val newR = 1 - (1 - r1) * (1 - r2)
val g1 = this.g()
val g2 = other.g()
val newG = 1 - (1 - g1) * (1 - g2)
val b1 = this.b()
val b2 = other.b()
val newB = 1 - (1 - b1) * (1 - b2)
return Light10B(newR, newG, newB)
}
private infix fun colSub(other: Light10B) = Light10B(
(this.rawR() - other.rawR()).clampChannel() ,
(this.rawG() - other.rawG()).clampChannel() ,
(this.rawB() - other.rawB()).clampChannel()
)
private infix fun colAdd(other: Light10B) = Light10B(
(this.rawR() + other.rawR()).clampChannel() ,
(this.rawG() + other.rawG()).clampChannel() ,
(this.rawB() + other.rawB()).clampChannel()
)
}

View File

@@ -228,11 +228,11 @@ object LightmapRenderer {
private fun calculate(x: Int, y: Int, doNotCalculateAmbient: Boolean): Int {
var lightLevelThis: Int = 0
val thisTerrain = Terrarum.ingame.map.getTileFromTerrain(x, y)
val thisWall = Terrarum.ingame.map.getTileFromWall(x, y)
val thisTerrain = Terrarum.ingame.world.getTileFromTerrain(x, y)
val thisWall = Terrarum.ingame.world.getTileFromWall(x, y)
val thisTileLuminosity = TilePropCodex.getProp(thisTerrain).luminosity
val thisTileOpacity = TilePropCodex.getProp(thisTerrain).opacity
val sunLight = Terrarum.ingame.map.globalLight
val sunLight = Terrarum.ingame.world.globalLight
// MIX TILE
// open air

View File

@@ -1,6 +1,6 @@
package net.torvald.terrarum.mapdrawer
import net.torvald.terrarum.gamemap.GameMap
import net.torvald.terrarum.gamemap.GameWorld
import net.torvald.terrarum.gamemap.PairedMapLayer
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.tileproperties.TileNameCode
@@ -20,7 +20,7 @@ import java.util.*
* Created by minjaesong on 16-01-19.
*/
object MapCamera {
val map: GameMap = Terrarum.ingame.map;
val WORLD: GameWorld = Terrarum.ingame.world;
var cameraX = 0
private set
@@ -38,9 +38,9 @@ object MapCamera {
var tilesetBook: Array<SpriteSheet> = arrayOf(tilesWall, tilesTerrain, tilesWire)
private set
val WALL = GameMap.WALL
val TERRAIN = GameMap.TERRAIN
val WIRE = GameMap.WIRE
val WALL = GameWorld.WALL
val TERRAIN = GameWorld.TERRAIN
val WIRE = GameWorld.WIRE
var renderWidth: Int = 0
private set
@@ -236,9 +236,9 @@ object MapCamera {
// position - (WH / 2)
cameraX = Math.round(FastMath.clamp(
player.hitbox.centeredX.toFloat() - renderWidth / 2, TSIZE.toFloat(), map.width * TSIZE - renderWidth - TSIZE.toFloat()))
player.hitbox.centeredX.toFloat() - renderWidth / 2, TSIZE.toFloat(), WORLD.width * TSIZE - renderWidth - TSIZE.toFloat()))
cameraY = Math.round(FastMath.clamp(
player.hitbox.centeredY.toFloat() - renderHeight / 2, TSIZE.toFloat(), map.height * TSIZE - renderHeight - TSIZE.toFloat()))
player.hitbox.centeredY.toFloat() - renderHeight / 2, TSIZE.toFloat(), WORLD.height * TSIZE - renderHeight - TSIZE.toFloat()))
}
fun renderBehind(gc: GameContainer, g: Graphics) {
@@ -272,11 +272,11 @@ object MapCamera {
val thisTile: Int?
if (mode % 3 == MapCamera.WALL)
thisTile = MapCamera.map.getTileFromWall(x, y)
thisTile = MapCamera.WORLD.getTileFromWall(x, y)
else if (mode % 3 == MapCamera.TERRAIN)
thisTile = MapCamera.map.getTileFromTerrain(x, y)
thisTile = MapCamera.WORLD.getTileFromTerrain(x, y)
else if (mode % 3 == MapCamera.WIRE)
thisTile = MapCamera.map.getTileFromWire(x, y)
thisTile = MapCamera.WORLD.getTileFromWire(x, y)
else
throw IllegalArgumentException()
@@ -352,10 +352,10 @@ object MapCamera {
*/
fun getNearbyTilesInfo(x: Int, y: Int, mode: Int, mark: Int?): Int {
val nearbyTiles = IntArray(4)
nearbyTiles[NEARBY_TILE_KEY_LEFT] = map.getTileFrom(mode, x - 1, y) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_RIGHT] = map.getTileFrom(mode, x + 1, y) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_UP] = map.getTileFrom(mode, x, y - 1) ?: 4906
nearbyTiles[NEARBY_TILE_KEY_DOWN] = map.getTileFrom(mode, x, y + 1) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_LEFT] = WORLD.getTileFrom(mode, x - 1, y) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_RIGHT] = WORLD.getTileFrom(mode, x + 1, y) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_UP] = WORLD.getTileFrom(mode, x, y - 1) ?: 4906
nearbyTiles[NEARBY_TILE_KEY_DOWN] = WORLD.getTileFrom(mode, x, y + 1) ?: 4096
// try for
var ret = 0
@@ -370,10 +370,10 @@ object MapCamera {
fun getNearbyTilesInfoNonSolid(x: Int, y: Int, mode: Int): Int {
val nearbyTiles = IntArray(4)
nearbyTiles[NEARBY_TILE_KEY_LEFT] = map.getTileFrom(mode, x - 1, y) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_RIGHT] = map.getTileFrom(mode, x + 1, y) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_UP] = map.getTileFrom(mode, x, y - 1) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_DOWN] = map.getTileFrom(mode, x, y + 1) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_LEFT] = WORLD.getTileFrom(mode, x - 1, y) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_RIGHT] = WORLD.getTileFrom(mode, x + 1, y) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_UP] = WORLD.getTileFrom(mode, x, y - 1) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_DOWN] = WORLD.getTileFrom(mode, x, y + 1) ?: 4096
// try for
var ret = 0
@@ -393,10 +393,10 @@ object MapCamera {
fun getNearbyTilesInfoWallSticker(x: Int, y: Int): Int {
val nearbyTiles = IntArray(4)
val NEARBY_TILE_KEY_BACK = NEARBY_TILE_KEY_UP
nearbyTiles[NEARBY_TILE_KEY_LEFT] = map.getTileFrom(TERRAIN, x - 1, y) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_RIGHT] = map.getTileFrom(TERRAIN, x + 1, y) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_DOWN] = map.getTileFrom(TERRAIN, x, y + 1) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_BACK] = map.getTileFrom(WALL, x, y) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_LEFT] = WORLD.getTileFrom(TERRAIN, x - 1, y) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_RIGHT] = WORLD.getTileFrom(TERRAIN, x + 1, y) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_DOWN] = WORLD.getTileFrom(TERRAIN, x, y + 1) ?: 4096
nearbyTiles[NEARBY_TILE_KEY_BACK] = WORLD.getTileFrom(WALL, x, y) ?: 4096
try {
if (TilePropCodex.getProp(nearbyTiles[NEARBY_TILE_KEY_DOWN]).isSolid)
@@ -442,8 +442,8 @@ object MapCamera {
fun clampW(x: Int): Int {
if (x < 0) {
return 0
} else if (x > map.width * TSIZE) {
return map.width * TSIZE
} else if (x > WORLD.width * TSIZE) {
return WORLD.width * TSIZE
} else {
return x
}
@@ -452,8 +452,8 @@ object MapCamera {
fun clampH(x: Int): Int {
if (x < 0) {
return 0
} else if (x > map.height * TSIZE) {
return map.height * TSIZE
} else if (x > WORLD.height * TSIZE) {
return WORLD.height * TSIZE
} else {
return x
}
@@ -462,8 +462,8 @@ object MapCamera {
fun clampWTile(x: Int): Int {
if (x < 0) {
return 0
} else if (x > map.width) {
return map.width
} else if (x > WORLD.width) {
return WORLD.width
} else {
return x
}
@@ -472,8 +472,8 @@ object MapCamera {
fun clampHTile(x: Int): Int {
if (x < 0) {
return 0
} else if (x > map.height) {
return map.height
} else if (x > WORLD.height) {
return WORLD.height
} else {
return x
}

View File

@@ -1,6 +1,6 @@
package net.torvald.terrarum.mapdrawer
import net.torvald.terrarum.gamemap.GameMap
import net.torvald.terrarum.gamemap.GameWorld
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.tileproperties.TileNameCode
import net.torvald.terrarum.tilestats.TileStats

View File

@@ -1,7 +1,7 @@
package net.torvald.terrarum.mapgenerator
import net.torvald.random.HQRNG
import net.torvald.terrarum.gamemap.GameMap
import net.torvald.terrarum.gamemap.GameWorld
import net.torvald.terrarum.tileproperties.TileNameCode
import com.jme3.math.FastMath
import com.sudoplay.joise.Joise
@@ -13,13 +13,13 @@ import java.util.*
object MapGenerator {
internal lateinit var map: GameMap
internal lateinit var world: GameWorld
internal lateinit var random: Random
//private static float[] noiseArray;
var SEED: Long = 0
set(value) {
field = value
map.generatorSeed = value
world.generatorSeed = value
}
var WIDTH: Int = 0
var HEIGHT: Int = 0
@@ -65,10 +65,10 @@ object MapGenerator {
internal val TILE_MACRO_ALL = -1
fun attachMap(map: GameMap) {
this.map = map
WIDTH = map.width
HEIGHT = map.height
fun attachMap(world: GameWorld) {
this.world = world
WIDTH = world.width
HEIGHT = world.height
val widthMulFactor = WIDTH / 8192f
@@ -154,7 +154,7 @@ object MapGenerator {
//wire layer
for (i in 0..HEIGHT - 1) {
for (j in 0..WIDTH - 1) {
map.wireArray[i][j] = 0
world.wireArray[i][j] = 0
}
}
@@ -486,11 +486,11 @@ object MapGenerator {
for (i in 0..HEIGHT - pillarOffset - 1) {
if (i < DIRT_LAYER_DEPTH) {
map.setTileTerrain(x, i + pillarOffset, TileNameCode.DIRT)
map.setTileWall(x, i + pillarOffset, TileNameCode.DIRT)
world.setTileTerrain(x, i + pillarOffset, TileNameCode.DIRT)
world.setTileWall(x, i + pillarOffset, TileNameCode.DIRT)
} else {
map.setTileTerrain(x, i + pillarOffset, TileNameCode.STONE)
map.setTileWall(x, i + pillarOffset, TileNameCode.STONE)
world.setTileTerrain(x, i + pillarOffset, TileNameCode.STONE)
world.setTileWall(x, i + pillarOffset, TileNameCode.STONE)
}
}
@@ -560,8 +560,8 @@ object MapGenerator {
val tile =
if (y < dirtStoneLine[x]) TileNameCode.DIRT
else TileNameCode.STONE
map.setTileTerrain(x, y, tile)
map.setTileWall(x, y, tile)
world.setTileTerrain(x, y, tile)
world.setTileWall(x, y, tile)
}
}
}
@@ -603,7 +603,7 @@ object MapGenerator {
}
if (noise > filter.getGrad(y, filterStart, filterEnd) * scarcity) {
map.setTileTerrain(x, y, tile)
world.setTileTerrain(x, y, tile)
}
}
}
@@ -633,8 +633,8 @@ object MapGenerator {
}
if (noise > filter.getGrad(y, filterStart, filterEnd) * scarcity
&& map.getTileFromTerrain(x, y) == replaceFrom) {
map.setTileTerrain(x, y, replaceTo)
&& world.getTileFromTerrain(x, y) == replaceFrom) {
world.setTileTerrain(x, y, replaceTo)
}
}
}
@@ -663,8 +663,8 @@ object MapGenerator {
else -> throw(IllegalArgumentException("[mapgenerator] Unknown noise module type '${noisemap.javaClass.simpleName}': Only the 'Joise' or 'TaggedSimplexNoise' is valid."))
}
if (noise > filter.getGrad(y, filterStart, filterEnd) * scarcity && map.getTileFromTerrain(x, y) == replaceFrom) {
map.setTileTerrain(x, y, tile[random.nextInt(tile.size)])
if (noise > filter.getGrad(y, filterStart, filterEnd) * scarcity && world.getTileFromTerrain(x, y) == replaceFrom) {
world.setTileTerrain(x, y, tile[random.nextInt(tile.size)])
}
}
}
@@ -721,8 +721,8 @@ object MapGenerator {
private fun generateFloatingIslands() {
println("[mapgenerator] Placing floating islands...")
val nIslandsMax = Math.round(map.width * 6f / 8192f)
val nIslandsMin = Math.max(2, Math.round(map.width * 4f / 8192f))
val nIslandsMax = Math.round(world.width * 6f / 8192f)
val nIslandsMin = Math.max(2, Math.round(world.width * 4f / 8192f))
val nIslands = random.nextInt(nIslandsMax - nIslandsMin) + nIslandsMin
val prevIndex = -1
@@ -735,13 +735,13 @@ object MapGenerator {
}
val island = FloatingIslandsPreset.generatePreset(currentIndex, random)
val startingPosX = random.nextInt(map.width - 2048) + 1024
val startingPosX = random.nextInt(world.width - 2048) + 1024
val startingPosY = minimumFloatingIsleHeight + random.nextInt(minimumFloatingIsleHeight)
for (j in island.indices) {
for (k in 0..island[0].size - 1) {
if (island[j][k] > 0) {
map.setTileTerrain(k + startingPosX, j + startingPosY, tiles[island[j][k]])
world.setTileTerrain(k + startingPosX, j + startingPosY, tiles[island[j][k]])
}
}
}
@@ -754,8 +754,8 @@ object MapGenerator {
println("[mapgenerator] Flooding bottom lava...")
for (i in HEIGHT * 14 / 15..HEIGHT - 1) {
for (j in 0..WIDTH - 1) {
if (map.terrainArray[i][j].toInt() == 0) {
map.setTileTerrain(j, i, TileNameCode.LAVA)
if (world.terrainArray[i][j].toInt() == 0) {
world.setTileTerrain(j, i, TileNameCode.LAVA)
}
}
}
@@ -773,18 +773,18 @@ object MapGenerator {
*/
for (y in TERRAIN_AVERAGE_HEIGHT - TERRAIN_UNDULATION..TERRAIN_AVERAGE_HEIGHT + TERRAIN_UNDULATION - 1) {
for (x in 0..map.width - 1) {
for (x in 0..world.width - 1) {
val thisTile = map.getTileFromTerrain(x, y)
val thisTile = world.getTileFromTerrain(x, y)
for (i in 0..8) {
var nearbyWallTile: Int?
nearbyWallTile = map.getTileFromWall(x + i % 3 - 1, y + i / 3 - 1)
nearbyWallTile = world.getTileFromWall(x + i % 3 - 1, y + i / 3 - 1)
if (nearbyWallTile == null) break;
if (i != 4 && thisTile == TileNameCode.DIRT && nearbyWallTile == TileNameCode.AIR) {
map.setTileTerrain(x, y, TileNameCode.GRASS)
world.setTileTerrain(x, y, TileNameCode.GRASS)
break
}
}
@@ -794,18 +794,18 @@ object MapGenerator {
}
private fun isGrassOrDirt(x: Int, y: Int): Boolean {
return map.getTileFromTerrain(x, y) == TileNameCode.GRASS || map.getTileFromTerrain(x, y) == TileNameCode.DIRT
return world.getTileFromTerrain(x, y) == TileNameCode.GRASS || world.getTileFromTerrain(x, y) == TileNameCode.DIRT
}
private fun replaceIfTerrain(ifTileRaw: Int, x: Int, y: Int, replaceTileRaw: Int) {
if (map.getTileFromTerrain(x, y) == ifTileRaw) {
map.setTileTerrain(x, y, replaceTileRaw)
if (world.getTileFromTerrain(x, y) == ifTileRaw) {
world.setTileTerrain(x, y, replaceTileRaw)
}
}
private fun replaceIfWall(ifTileRaw: Int, x: Int, y: Int, replaceTileRaw: Int) {
if (map.getTileFromWall(x, y) == ifTileRaw) {
map.setTileWall(x, y, replaceTileRaw)
if (world.getTileFromWall(x, y) == ifTileRaw) {
world.setTileWall(x, y, replaceTileRaw)
}
}
@@ -837,11 +837,11 @@ object MapGenerator {
if (ix < OCEAN_WIDTH) {
if (worldOceanPosition == TYPE_OCEAN_LEFT) {
for (y in getTerrainHeightFromHeightMap(OCEAN_WIDTH)..getTerrainHeightFromHeightMap(ix) - 1) {
map.setTileTerrain(ix, y, TileNameCode.WATER)
world.setTileTerrain(ix, y, TileNameCode.WATER)
}
} else if (worldOceanPosition == TYPE_OCEAN_RIGHT) {
for (y in getTerrainHeightFromHeightMap(map.width - 1 - OCEAN_WIDTH)..getTerrainHeightFromHeightMap(map.width - 1 - ix) - 1) {
map.setTileTerrain(map.width - 1 - ix, y, TileNameCode.WATER)
for (y in getTerrainHeightFromHeightMap(world.width - 1 - OCEAN_WIDTH)..getTerrainHeightFromHeightMap(world.width - 1 - ix) - 1) {
world.setTileTerrain(world.width - 1 - ix, y, TileNameCode.WATER)
}
}
}
@@ -852,15 +852,15 @@ object MapGenerator {
val terrainPoint = getTerrainHeightFromHeightMap(ix)
map.setTileTerrain(ix, terrainPoint + iy, thisSand)
world.setTileTerrain(ix, terrainPoint + iy, thisSand)
// clear grass and make the sheet thicker
map.setTileTerrain(ix, terrainPoint + iy - 1, thisSand)
world.setTileTerrain(ix, terrainPoint + iy - 1, thisSand)
} else if (worldOceanPosition == TYPE_OCEAN_RIGHT) {
val terrainPoint = getTerrainHeightFromHeightMap(map.width - 1 - ix)
val terrainPoint = getTerrainHeightFromHeightMap(world.width - 1 - ix)
map.setTileTerrain(map.width - 1 - ix, terrainPoint + iy, thisSand)
world.setTileTerrain(world.width - 1 - ix, terrainPoint + iy, thisSand)
// clear grass and make the sheet thicker
map.setTileTerrain(map.width - 1 - ix, terrainPoint + iy - 1, thisSand)
world.setTileTerrain(world.width - 1 - ix, terrainPoint + iy - 1, thisSand)
}
}
ix++
@@ -868,7 +868,7 @@ object MapGenerator {
}
private fun freeze() {
for (y in 0..map.height - 1 - 1) {
for (y in 0..world.height - 1 - 1) {
for (x in 0..getFrozenAreaWidth(y) - 1) {
if (worldOceanPosition == TYPE_OCEAN_RIGHT) {
replaceIfTerrain(TileNameCode.DIRT, x, y, TileNameCode.SNOW)
@@ -877,11 +877,11 @@ object MapGenerator {
replaceIfWall(TileNameCode.DIRT, x, y, TileNameCode.SNOW)
replaceIfWall(TileNameCode.STONE, x, y, TileNameCode.ICE_NATURAL)
} else {
replaceIfTerrain(TileNameCode.DIRT, map.width - 1 - x, y, TileNameCode.SNOW)
replaceIfTerrain(TileNameCode.STONE, map.width - 1 - x, y, TileNameCode.ICE_NATURAL)
replaceIfTerrain(TileNameCode.DIRT, world.width - 1 - x, y, TileNameCode.SNOW)
replaceIfTerrain(TileNameCode.STONE, world.width - 1 - x, y, TileNameCode.ICE_NATURAL)
replaceIfWall(TileNameCode.DIRT, map.width - 1 - x, y, TileNameCode.SNOW)
replaceIfWall(TileNameCode.STONE, map.width - 1 - x, y, TileNameCode.ICE_NATURAL)
replaceIfWall(TileNameCode.DIRT, world.width - 1 - x, y, TileNameCode.SNOW)
replaceIfWall(TileNameCode.STONE, world.width - 1 - x, y, TileNameCode.ICE_NATURAL)
}
}
}
@@ -899,7 +899,7 @@ object MapGenerator {
if (worldOceanPosition == TYPE_OCEAN_RIGHT) {
height = getTerrainHeightFromHeightMap(width)
} else {
height = getTerrainHeightFromHeightMap(map.width - 1 - width)
height = getTerrainHeightFromHeightMap(world.width - 1 - width)
}
val k = width / FastMath.sqrt(height.toFloat())
@@ -948,8 +948,8 @@ object MapGenerator {
&& Math.round(j + pointerX - halfBrushSize) < WIDTH - brushSize
&& Math.round(i + pointerY - halfBrushSize) > brushSize
&& Math.round(i + pointerY - halfBrushSize) < HEIGHT - brushSize) {
if (map.terrainArray[Math.round(i + pointerY - halfBrushSize)][Math.round(j + pointerX - halfBrushSize)] == fillFrom.toByte()) {
map.terrainArray[Math.round(i + pointerY - halfBrushSize)][Math.round(j + pointerX - halfBrushSize)] = fill.toByte()
if (world.terrainArray[Math.round(i + pointerY - halfBrushSize)][Math.round(j + pointerX - halfBrushSize)] == fillFrom.toByte()) {
world.terrainArray[Math.round(i + pointerY - halfBrushSize)][Math.round(j + pointerX - halfBrushSize)] = fill.toByte()
}
}
}

View File

@@ -38,15 +38,15 @@ class ThreadProcessNoiseLayers(val startIndex: Int, val endIndex: Int,
for (i in 0..fromTerr.size - 1) {
val fromTerrVariable = fromTerr[i]
if ((MapGenerator.map.getTileFromTerrain(x, y) == fromTerrVariable || fromTerrVariable == MapGenerator.TILE_MACRO_ALL)
&& (MapGenerator.map.getTileFromWall(x, y) == fromWall || fromWall == MapGenerator.TILE_MACRO_ALL)) {
MapGenerator.map.setTileTerrain(x, y, to)
if ((MapGenerator.world.getTileFromTerrain(x, y) == fromTerrVariable || fromTerrVariable == MapGenerator.TILE_MACRO_ALL)
&& (MapGenerator.world.getTileFromWall(x, y) == fromWall || fromWall == MapGenerator.TILE_MACRO_ALL)) {
MapGenerator.world.setTileTerrain(x, y, to)
}
}
}
else if ((MapGenerator.map.getTileFromTerrain(x, y) == fromTerr || fromTerr == MapGenerator.TILE_MACRO_ALL)
&& (MapGenerator.map.getTileFromWall(x, y) == fromWall || fromWall == MapGenerator.TILE_MACRO_ALL)) {
MapGenerator.map.setTileTerrain(x, y, to)
else if ((MapGenerator.world.getTileFromTerrain(x, y) == fromTerr || fromTerr == MapGenerator.TILE_MACRO_ALL)
&& (MapGenerator.world.getTileFromWall(x, y) == fromWall || fromWall == MapGenerator.TILE_MACRO_ALL)) {
MapGenerator.world.setTileTerrain(x, y, to)
}
}
}

View File

@@ -12,9 +12,9 @@ object RealEstateCodex {
*
* Note that a tile can have only ONE owner (as an Actor or Faction ID)
*/
private var ownershipRegistry: HashMap<Long, Long> = HashMap()
private var ownershipRegistry: HashMap<Long, Int> = HashMap()
fun setOwner(tileX: Int, tileY: Int, refID: Long) {
fun setOwner(tileX: Int, tileY: Int, refID: Int) {
ownershipRegistry[RealEstateUtility.getAbsoluteTileNumber(tileX, tileY)] = refID
}
@@ -22,6 +22,6 @@ object RealEstateCodex {
ownershipRegistry.remove(RealEstateUtility.getAbsoluteTileNumber(tileX, tileY))
}
fun getOwner(tileX: Int, tileY: Int): Long? =
fun getOwner(tileX: Int, tileY: Int): Int? =
ownershipRegistry[RealEstateUtility.getAbsoluteTileNumber(tileX, tileY)]
}

View File

@@ -8,10 +8,10 @@ import net.torvald.terrarum.gameactors.faction.FactionCodex
*/
object RealEstateUtility {
fun getAbsoluteTileNumber(x: Int, y: Int): Long =
(Terrarum.ingame.map.width * y).toLong() + x
(Terrarum.ingame.world.width * y).toLong() + x
fun resolveAbsoluteTileNumber(t: Long): Pair<Int, Int> =
Pair((t % Terrarum.ingame.map.width).toInt(), (t / Terrarum.ingame.map.width).toInt())
Pair((t % Terrarum.ingame.world.width).toInt(), (t / Terrarum.ingame.world.width).toInt())
/**
* Get owner ID as an Actor/Faction

View File

@@ -5,6 +5,7 @@ import net.torvald.random.HQRNG
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gamemap.WorldTime
import net.torvald.terrarum.mapdrawer.LightmapRenderer
import net.torvald.terrarum.weather.WeatherMixer
/**
* Created by minjaesong on 16-06-16.
@@ -92,8 +93,8 @@ object TilePropUtil {
fun getDynamicLumFunc(baseLum: Int, type: Int): Int {
return when (type) {
1 -> getTorchFlicker(baseLum)
2 -> Terrarum.ingame.map.globalLight // current global light
3 -> Terrarum.ingame.globalLightByTime(WorldTime.DAY_LENGTH / 2) // daylight at noon
2 -> Terrarum.ingame.world.globalLight // current global light
3 -> WeatherMixer.getGlobalLightOfTime(WorldTime.DAY_LENGTH / 2).toInt() // daylight at noon
4 -> getSlowBreath(baseLum)
5 -> getPulsate(baseLum)
else -> baseLum

View File

@@ -1,7 +1,7 @@
package net.torvald.terrarum.tilestats
import net.torvald.terrarum.gameactors.Player
import net.torvald.terrarum.gamemap.GameMap
import net.torvald.terrarum.gamemap.GameWorld
import net.torvald.terrarum.gamemap.MapLayer
import net.torvald.terrarum.mapdrawer.MapCamera
import net.torvald.terrarum.mapdrawer.MapDrawer
@@ -15,7 +15,7 @@ import java.util.Arrays
*/
object TileStats {
private val tilestat = ShortArray(GameMap.TILES_SUPPORTED)
private val tilestat = ShortArray(GameWorld.TILES_SUPPORTED)
private val TSIZE = MapDrawer.TILE_SIZE
@@ -27,7 +27,7 @@ object TileStats {
// Get stats on no-zoomed screen area. In other words, will behave as if screen zoom were 1.0
// no matter how the screen is zoomed.
val map = Terrarum.ingame.map
val map = Terrarum.ingame.world
val player = Terrarum.ingame.player
val renderWidth = FastMath.ceil(Terrarum.WIDTH.toFloat())

View File

@@ -114,7 +114,7 @@ class BasicDebugInfoWindow:UICanvas {
printLine(g, 7, "light@cursor $ccG$lightVal")
val tileNo: String
val tileNumRaw = Terrarum.ingame.map.getTileFromTerrain(mouseTileX, mouseTileY) ?: -1
val tileNumRaw = Terrarum.ingame.world.getTileFromTerrain(mouseTileX, mouseTileY) ?: -1
val tilenum = tileNumRaw / PairedMapLayer.RANGE
val tiledmg = tileNumRaw % PairedMapLayer.RANGE
tileNo = if (tileNumRaw == -1) "" else "$tilenum:$tiledmg"
@@ -127,8 +127,8 @@ class BasicDebugInfoWindow:UICanvas {
printLineColumn(g, 2, 1, "VSync $ccG" + Terrarum.appgc.isVSyncRequested)
printLineColumn(g, 2, 2, "Env colour temp $ccG" + MapDrawer.getColTemp())
printLineColumn(g, 2, 5, "Time $ccG${Terrarum.ingame.map.worldTime.elapsedSeconds()}" +
" (${Terrarum.ingame.map.worldTime.getFormattedTime()})")
printLineColumn(g, 2, 5, "Time $ccG${Terrarum.ingame.world.time.elapsedSeconds()}" +
" (${Terrarum.ingame.world.time.getFormattedTime()})")
printLineColumn(g, 2, 6, "Mass $ccG${player.mass}")
drawHistogram(g, LightmapRenderer.histogram,

View File

@@ -1,5 +1,6 @@
package net.torvald.terrarum.ui
import net.torvald.gadgets.HistoryArray
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.console.CommandInterpreter
@@ -16,16 +17,16 @@ class ConsoleWindow : UICanvas, UITypable {
internal var UIColour = Color(0xCC000000.toInt())
private var commandInputPool: StringBuilder? = null
private var prevCommand: String? = null
private var inputCursorPos: Int = 0
private val MESSAGES_MAX = 5000
private val COMMAND_HISTORY_MAX = 100
private var messages = Array(MESSAGES_MAX, {""})
private var messageDisplayPos: Int = 0
private var messagesCount: Int = 0
private var commandInputPool: StringBuilder? = null
private var commandHistory = HistoryArray<String>(COMMAND_HISTORY_MAX)
private val LINE_HEIGHT = 20
private val MESSAGES_DISPLAY_COUNT = 9
@@ -38,6 +39,9 @@ class ConsoleWindow : UICanvas, UITypable {
private var drawOffY: Float = -height.toFloat()
private var openingTimeCounter = 0
private var historyIndex = -1
init {
reset()
}
@@ -70,15 +74,25 @@ class ConsoleWindow : UICanvas, UITypable {
override fun keyPressed(key: Int, c: Char) {
// history
if (key == Key.UP && historyIndex < commandHistory.history.size)
historyIndex++
else if (key == Key.DOWN && historyIndex >= 0)
historyIndex--
else if (key != Key.UP && key != Key.DOWN)
historyIndex = -1
// execute
if (key == Key.RET && commandInputPool!!.length > 0) {
prevCommand = commandInputPool!!.toString()
commandHistory.add(commandInputPool!!.toString())
executeCommand()
commandInputPool = StringBuilder()
}
else if (key == Key.BKSP && commandInputPool!!.length > 0) {
// erase last letter
else if (key == Key.BACKSPACE && commandInputPool!!.length > 0) {
commandInputPool!!.deleteCharAt(commandInputPool!!.length - 1)
}
// append acceptable letter
else if (key >= 2 && key <= 13
|| key >= 16 && key <= 27
|| key >= 30 && key <= 40
@@ -87,20 +101,25 @@ class ConsoleWindow : UICanvas, UITypable {
commandInputPool!!.append(c)
inputCursorPos += 1
}
else if (key == Key.UP) {
// scroll
else if (key == Key.UP || key == Key.DOWN) {
// create new stringbuilder
commandInputPool = StringBuilder()
commandInputPool!!.append(prevCommand)
if (historyIndex >= 0) // just leave blank if index is -1
commandInputPool!!.append(commandHistory[historyIndex] ?: "")
}
// delete input
else if (key == Key.DELETE) {
commandInputPool = StringBuilder()
}
// message scroll up
else if (key == Key.PGUP) {
setDisplayPos(-MESSAGES_DISPLAY_COUNT + 1)
}
// message scroll down
else if (key == Key.PGDN) {
setDisplayPos(MESSAGES_DISPLAY_COUNT - 1)
}// scroll down
// scroll up
// prev command
// get input
// backspace
}
}
override fun keyReleased(key: Int, c: Char) {
@@ -148,7 +167,7 @@ class ConsoleWindow : UICanvas, UITypable {
messageDisplayPos = 0
messagesCount = 0
inputCursorPos = 0
prevCommand = ""
commandHistory = HistoryArray<String>(COMMAND_HISTORY_MAX)
commandInputPool = StringBuilder()
if (Terrarum.ingame.auth.b()) sendMessage(Lang["DEV_MESSAGE_CONSOLE_CODEX"])

View File

@@ -54,7 +54,8 @@ constructor(val UI: UICanvas) {
println("[UIHandler] Creating UI '${UI.javaClass.simpleName}'")
UIDrawnCanvas = Image(
FastMath.nearestPowerOfTwo(UI.width), FastMath.nearestPowerOfTwo(UI.height))
//FastMath.nearestPowerOfTwo(UI.width), FastMath.nearestPowerOfTwo(UI.height))
UI.width, UI.height)
UIGraphicInstance = UIDrawnCanvas.graphics
}

View File

@@ -0,0 +1,18 @@
package net.torvald.terrarum.weather
import org.newdawn.slick.Image
import java.util.*
/**
* Note: Colour maps are likely to have sparse data points
* (i.e., they have 2 475 px in width and you'll need 79 200 data points for a day)
* so between two must be interpolated.
*
* Created by minjaesong on 16-07-11.
*/
data class BaseModularWeather(
val globalLightColourMap: Image,
var skyboxGradColourMap: Image,
val classification: String,
var extraImages: ArrayList<Image>
)

View File

@@ -0,0 +1,155 @@
package net.torvald.terrarum.weather
import com.jme3.math.FastMath
import net.torvald.JsonFetcher
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gamemap.WorldTime
import net.torvald.terrarum.mapdrawer.Light10B
import org.newdawn.slick.Color
import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics
import org.newdawn.slick.Image
import org.newdawn.slick.fills.GradientFill
import org.newdawn.slick.geom.Rectangle
import java.util.*
/**
* Current, next are there for cross-fading two weathers
*
* Created by minjaesong on 16-07-11.
*/
object WeatherMixer {
lateinit var weatherList: ArrayList<BaseModularWeather>
lateinit var currentWeather: BaseModularWeather
lateinit var nextWeather: BaseModularWeather
private var skyBoxCurrent = Rectangle(0f, 0f, Terrarum.WIDTH.toFloat(), Terrarum.HEIGHT.toFloat())
private var skyBoxNext = Rectangle(0f, 0f, Terrarum.WIDTH.toFloat(), Terrarum.HEIGHT.toFloat())
val globalLightNow = Light10B(0)
// Weather indices
const val WEATHER_GENERIC = 0
// TODO add weather indices manually
const val RAW_DIR = "./res/raw/weathers"
init {
weatherList = ArrayList()
// TODO read weather descriptions from res/weather (modular weather)
// test: read only one
weatherList.add(readFromJson("$RAW_DIR/WeatherGeneric.json"))
// initialise
currentWeather = weatherList[WEATHER_GENERIC]
// nextWeather = %&)(@$*%&$(*%
}
fun update(gc: GameContainer, delta: Int) {
currentWeather = weatherList[WEATHER_GENERIC]
}
fun render(g: Graphics) {
// we will not care for nextSkybox for now
val timeNow = Terrarum.ingame.world.time.elapsedSeconds()
val skyboxColourMap = currentWeather.skyboxGradColourMap
val lightColourMap = currentWeather.globalLightColourMap
// draw skybox to provided (should be main) graphics instance
val skyColourFill = GradientFill(
0f, 0f,
getGradientColour(skyboxColourMap, 0, timeNow),
0f, Terrarum.HEIGHT.toFloat(),
getGradientColour(skyboxColourMap, 1, timeNow)
)
g.fill(skyBoxCurrent, skyColourFill)
// calculate global light
globalLightNow.fromSlickColor(getGradientColour(lightColourMap, 0, timeNow))
}
fun getGlobalLightOfTime(timeInSec: Int): Light10B =
Light10B(getGradientColour(currentWeather.globalLightColourMap, 0, timeInSec))
fun getGradientColour(image: Image, row: Int, timeInSec: Int): Color {
val gradMapWidth = image.width
val phaseThis = Math.round(
timeInSec.toFloat() / WorldTime.DAY_LENGTH.toFloat() * gradMapWidth
)
val phaseNext = (phaseThis + 1) % WorldTime.DAY_LENGTH
val dataPointDistance = WorldTime.DAY_LENGTH / image.width
val colourThis = image.getColor(phaseThis, row)
val colourNext = image.getColor(phaseNext, row)
// interpolate R, G and B
val scale = (timeInSec % dataPointDistance).toFloat() / dataPointDistance
val retColour = Color(0)
retColour.r = FastMath.interpolateLinear(scale, colourThis.r, colourNext.r)
retColour.g = FastMath.interpolateLinear(scale, colourThis.g, colourNext.g)
retColour.b = FastMath.interpolateLinear(scale, colourThis.b, colourNext.b)
return retColour
}
fun readFromJson(path: String): BaseModularWeather {
/* JSON structure:
{
"globalLight": "colourmap/sky_colour.png", // integer for static, string (path to image) for dynamic
"skyboxGradColourMap": "colourmap/sky_colour.png", // integer for static, string (path to image) for dynamic
"extraImages": [
// if any, it will be like:
sun01.png,
clouds01.png,
clouds02.png,
auroraBlueViolet.png
]
}
*/
val pathToImage = "./res/graphics/weathers"
val JSON = JsonFetcher.readJson(path)
val globalLightInJson = JSON.get("globalLight").asJsonPrimitive
val skyboxInJson = JSON.get("skyboxGradColourMap").asJsonPrimitive
val extraImagesPath = JSON.getAsJsonArray("extraImages")
val globalLight: Image
val skybox: Image
val extraImages = ArrayList<Image>()
val classification = JSON.get("classification").asJsonPrimitive.asString
// parse globalLight
if (globalLightInJson.isString)
globalLight = Image("$pathToImage/${globalLightInJson.asString}")
else if (globalLightInJson.isNumber) {
// make 1x1 image with specified colour
globalLight = Image(1, 1)
globalLight.graphics.color = Color(globalLightInJson.asNumber.toInt())
globalLight.graphics.fillRect(0f, 0f, 1f, 1f)
}
else
throw IllegalStateException("In weather descriptor $path -- globalLight seems malformed.")
// parse skyboxGradColourMap
if (skyboxInJson.isString)
skybox = Image("$pathToImage/${skyboxInJson.asString}")
else if (globalLightInJson.isNumber) {
// make 1x2 image with specified colour
skybox = Image(1, 2)
skybox.graphics.color = Color(skyboxInJson.asNumber.toInt())
skybox.graphics.fillRect(0f, 0f, 1f, 2f)
}
else
throw IllegalStateException("In weather descriptor $path -- skyboxGradColourMap seems malformed.")
// get extra images
for (i in extraImagesPath)
extraImages.add(Image("$pathToImage/$i"))
return BaseModularWeather(globalLight, skybox, classification, extraImages)
}
}

Binary file not shown.

Binary file not shown.

View File

@@ -11,12 +11,12 @@
</imagelayer>
<layer name="Wall" width="512" height="100">
<data encoding="base64" compression="zlib">
eJzt2TEOwjAQRcEYTsL9L4loECBsLGC9gZ2RfpUi7p6jbBsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQ4dTaddWeAUBVe+qx/gNAjNseVhsAVJXd4MwBQFXZDc4cAFSV3eDMAUBV2Q2+rB3vt+q9AFDVqtY+22P3V98DAKCq6Mb29qr9K+4AAFBVZF9H038AyBPZ19H0HwDyRPZ1NP0HgDyRfR1N/wEgT6+Lo2Z+49ls/yPPAgBV6T8A1KP/AFBPr5HR8/8fAPJE9nU0/QeAtSKbOjv9B4C1Ips6O/0HgLUimzo7/QeAtSKbOrs2ucgzAMCva4d2t1mRfR3N9z8AfO7d/u+d/gNAn/5rPwD1/Gv/AYA+/QcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPnEGIseuBw==
eJzt2TEOwjAURMEYTsT9L4egQKQwigD7G3ZG2spNuufI2wYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUuLT2WNoZAKRaqcf6DwBjPPcwbQCQqrrB+g8A81U3WP8BYL7qBus/AMxX3eDb2nk//QeAsVbq/ux7AACkWrX9M+4AAJBK/wEgj/4DQB79B4A8+g8AeXpdfNXMb5wd7f/IbwGAVPoPAHn0HwDy9Bo5et7/AaCO/gNAhqrm6z8A1Kluv/4DwHzV7dd/AJivuv33/h+c/gNAXzu13Y7y/w8Av+vd/q9O/wGgT/+1H4A8/9p/AKBP/wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAT1wBJRX8Bw==
</data>
</layer>
<layer name="Terrain" width="512" height="100">
<data encoding="base64" compression="zlib">
eJzt3WtrE0EYhuHdtKhEWvCAYL7VA1LB///3TNDFsG7SPUx23p25brjwS9VASZ7ZNEmbRpIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSVIJvd/lvgWSJGntTvvvDCBJUj2ddr+1/5IkVZX9lySprrrtb50BJEmqpv7+OwNIklR2Q9vf7b8zgCRJZXZp/50BpHr72TbNl6Nvbe5bIukWXdt+PweQ6u35uPtPR1/tv1RU3XX9S9vvDCDVmf2XymvK7jsDSHVm/6Vt1F3PjzFn+9vev9H/fyWVlf2X4rdk01OcBTw3IJWX/ZfitvR6PvV5QFI5Rdv//V3TvPrr/i73rZHyFWn77b9UXlH2v9v912eb/+AcoEqLtv3OAFJ55d7/x4Hd7/fgDKCKirr99l8qq9z7P7a39l+FF3n3nQGk8rL/Up5SvWfPGUDSnOy/dL3D7v+tHnKtlO/Rj8D+S9sv5/5/2DfNp/2fbf94/PPdBd3XSGt3mLiJt/hMnojsv7T9Ilz/j9l2+68cfQ6wtVGNfe5Dqq2t3C/svzTclGv/2m3l8U5K1Zjn+iLdL7rf9Xvuyf5Lg7n2dwaQ+s35mV6Ens/2vs/+S/9y7Z/+DOBsoK2V6nU8Efp13PjvF/zIvP9e/6co2f40Z4Chx03PEShSa71mV8M9vvDZf12nzwB84wygG3ZIfJ/n+vkgUlN+t/KU930qfxHekyMpbq75850Dcu5rii1wFohXtPfdSopT/zN9cj8+cNmSa/O1P5PhlrfV8xDD5byuH0vSul373L7cjweQUmnnhZxnuCjfn9T67/3r263g/ux1hvuFf19lNvbzdkt4XIBccu+R++66Lr33r7PW7ei2vJ3JOWFeqXbVfR9gW6Ls/1qWPj9R2u7m/n4AkEdt+z/X3J9t2F0AIrL/AFAf+w8A9bH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAq/AQvXoTU=
eJzt3dtu00AUhlG7rQAFtRJQIZG34Ir3fzOIiqViHMdxJt7bM+uTlrjhEKlK/nFOdJ0kSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZKkGvr6EH0LJEnS1p323xlAkqR2Ou1+b/8lSWoq+y9JUlsN2987A0iS1Ezj/XcGkCSp7qa2f9h/ZwBJkurs3P47A0jt9rN/86uPviWS7tHc9nsdQGo3+y/V2XBdf2n7nQGkNrP/Un1ds/vOAFKb2X9pHw3X80us2f5+9HeM/11JdWX/pfzdsuklzgKeG5Dqy/5Lebv1er70eUBSPWXb/8Nj13346+kx+tZIcWXafvsv1VeW/R92/+O7zX92DlCjZdt+ZwCpvqL3/2Vi98c9OwOoobJuv/2X6ip6/5f22f6r8jLvvjOAVF/2X4qp1Gf2nAEkrcn+S/MdH/7f6ilzlfyMfgb2X9p/kfv/7dB13w9v2/7659cvZwy/R9q645WbeI/v5MnI/kv7L8P1/5Jtt/+K6EeCrc1q6XMfUmvt5X5h/6Xprrn2b91eHu+kUi15ri/T/WLY+in2X/o31/7OANK4Na/pZcj+S8ty7V/+DOBsoL1V6n08Gcq8/97/pyzZ/jJngKnHTc8RKFNbvWdX071c+O6/odN3AH5yBtAdOxa+zzN/PsjUNf+38jWf+1R8GT6TIylvrvnjzgGR+1piC5wF8pXtc7eS8jT+Tp/oxwfOu+XafOvvZLjnbfU8xHSR1/VLSdq2ue/ti348gJJqOy9EnuGy/HxKm3v/38nDBp7evc/wcOOfV50t/b7dGh4XIEr0HrnvbuvS/m91O4Yt71dyTlhXqV113wfYlyz7v5Vbn5+obXejfx4AxGht/9da+9qG3QUgI/sPAO2x/wDQHvsPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlPAbDVyojQ==
</data>
</layer>
</map>