diff --git a/assets/graphics/fonts/han_johab.png b/assets/graphics/fonts/han_johab.png index 9793c376e..7a88ba2d3 100644 Binary files a/assets/graphics/fonts/han_johab.png and b/assets/graphics/fonts/han_johab.png differ diff --git a/assets/graphics/fonts/kana.png b/assets/graphics/fonts/kana.png index 3b70966c1..af8317eb9 100644 Binary files a/assets/graphics/fonts/kana.png and b/assets/graphics/fonts/kana.png differ diff --git a/assets/graphics/gui/control_helper_body.png b/assets/graphics/gui/control_helper_body.png index eee62b27f..1c0ba6e35 100644 Binary files a/assets/graphics/gui/control_helper_body.png and b/assets/graphics/gui/control_helper_body.png differ diff --git a/assets/graphics/gui/control_helper_left b/assets/graphics/gui/control_helper_left index e377c82d5..48b36b393 100644 Binary files a/assets/graphics/gui/control_helper_left and b/assets/graphics/gui/control_helper_left differ diff --git a/assets/graphics/gui/control_helper_right.png b/assets/graphics/gui/control_helper_right.png index 87df8157d..3dde6c237 100644 Binary files a/assets/graphics/gui/control_helper_right.png and b/assets/graphics/gui/control_helper_right.png differ diff --git a/assets/graphics/gui/health_distance.png b/assets/graphics/gui/health_distance.png new file mode 100644 index 000000000..0dfdd5d58 Binary files /dev/null and b/assets/graphics/gui/health_distance.png differ diff --git a/assets/graphics/gui/health_take_a_break.png b/assets/graphics/gui/health_take_a_break.png new file mode 100644 index 000000000..c72e02eaa Binary files /dev/null and b/assets/graphics/gui/health_take_a_break.png differ diff --git a/assets/graphics/gui/progress_round_sheet.png b/assets/graphics/gui/progress_round_sheet.png index d19e06cf7..3f62f8cec 100644 Binary files a/assets/graphics/gui/progress_round_sheet.png and b/assets/graphics/gui/progress_round_sheet.png differ diff --git a/assets/graphics/weathers/raindrop.png b/assets/graphics/weathers/raindrop.png new file mode 100644 index 000000000..97d09416d Binary files /dev/null and b/assets/graphics/weathers/raindrop.png differ diff --git a/assets/raw/weathers/WeatherGenericRain.json.asrtinears b/assets/raw/weathers/WeatherGenericRain.json.asrtinears new file mode 100644 index 000000000..b4a791cbc --- /dev/null +++ b/assets/raw/weathers/WeatherGenericRain.json.asrtinears @@ -0,0 +1,10 @@ +{ + "globalLight": "generic_light.png", + "skyboxGradColourMap": "generic_skybox.png", + "classification": "genericrain", + "extraImages": [ + "raindrop.png" + ], + "mixFrom": "__CURRENTWEATHER", + "mixPercentage": 80.0 +} \ No newline at end of file diff --git a/assets/sounds/test/.gitattributes b/assets/sounds/test/.gitattributes new file mode 100644 index 000000000..ca82ef549 --- /dev/null +++ b/assets/sounds/test/.gitattributes @@ -0,0 +1 @@ +*.{psd,tga,ogg} filter=lfs diff=lfs merge=lfs -text \ No newline at end of file diff --git a/assets/sounds/test/2ND_PM.xm b/assets/sounds/test/2ND_PM.xm new file mode 100644 index 000000000..a344f691d Binary files /dev/null and b/assets/sounds/test/2ND_PM.xm differ diff --git a/assets/sounds/test/GSLINGER.MOD b/assets/sounds/test/GSLINGER.MOD new file mode 100644 index 000000000..dc3007120 Binary files /dev/null and b/assets/sounds/test/GSLINGER.MOD differ diff --git a/assets/sounds/test/bad_apple.xm b/assets/sounds/test/bad_apple.xm new file mode 100644 index 000000000..087f016ad Binary files /dev/null and b/assets/sounds/test/bad_apple.xm differ diff --git a/assets/sounds/test/bb.xm b/assets/sounds/test/bb.xm new file mode 100644 index 000000000..c44955a73 Binary files /dev/null and b/assets/sounds/test/bb.xm differ diff --git a/assets/sounds/test/keys_to_imagination.mod b/assets/sounds/test/keys_to_imagination.mod new file mode 100644 index 000000000..440569ce8 Binary files /dev/null and b/assets/sounds/test/keys_to_imagination.mod differ diff --git a/assets/sounds/test/zelda_fds.xm b/assets/sounds/test/zelda_fds.xm new file mode 100644 index 000000000..c5080a8ab Binary files /dev/null and b/assets/sounds/test/zelda_fds.xm differ diff --git a/src/net/torvald/imagefont/GameFontBase.kt b/src/net/torvald/imagefont/GameFontBase.kt index 486d8bfa5..f812adef2 100644 --- a/src/net/torvald/imagefont/GameFontBase.kt +++ b/src/net/torvald/imagefont/GameFontBase.kt @@ -154,11 +154,6 @@ constructor() : Font { 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) @@ -168,8 +163,8 @@ constructor() : Font { for (i in 0..endIndex - 1) { val ctype = getSheetType(s[i]) - if (i > 0 && s[i].toInt() > 0x20) { - // Unihan-hangul Kerning + /*if (i > 0 && s[i].toInt() > 0x20) { + // inter-Unihan-hangul Kerning val cpre = getSheetType(s[i - 1]) if ((unihanWidthSheets.contains(cpre) || cpre == SHEET_HANGUL) && !(unihanWidthSheets.contains(ctype) || ctype == SHEET_HANGUL) @@ -182,18 +177,22 @@ constructor() : Font { len += 1 } - } + }*/ if (zeroWidthSheets.contains(ctype)) len += 0 else if (narrowWidthSheets.contains(ctype)) len += W_LATIN_NARROW - else if (cjkWidthSheets.contains(ctype)) - len += W_CJK + else if (ctype == SHEET_CJK_PUNCT) + len += W_ASIAN_PUNCT + else if (ctype == SHEET_HANGUL) + len += W_HANGUL + else if (ctype == SHEET_KANA) + len += W_KANA else if (unihanWidthSheets.contains(ctype)) len += W_UNIHAN else if (isThaiDiacritics(s[i])) - len = len // set width of the glyph as -W_LATIN_WIDE + len += 0 // set width of the glyph as -W_LATIN_WIDE else len += W_LATIN_WIDE @@ -237,7 +236,7 @@ constructor() : Font { val jungRow = getHanMedialRow(hIndex) val jongRow = getHanFinalRow(hIndex) - val glyphW = getWidth("" + ch) + val glyphW = getWidth(ch.toString()) /*// initials hangulSheet.renderInUse( @@ -453,11 +452,11 @@ constructor() : Font { sheetX, sheetY )*/ sheetKey[prevInstance]!!.getSubImage(sheetX, sheetY).draw( - Math.round(x + getWidthSubstr(s, i + 1) - glyphW).toFloat() // Interchar: pull punct right next to hangul to the left - + if (i > 0 && isHangul(s[i - 1])) -3f - else 0f, + Math.round(x + getWidthSubstr(s, i + 1) - glyphW).toFloat(), + // to deal with the height difference of the sheets Math.round(y).toFloat() + (if (prevInstance == SHEET_CJK_PUNCT) -1 + else if (prevInstance == SHEET_FW_UNI) (H - H_HANGUL) / 2 else 0).toFloat(), @@ -589,10 +588,13 @@ constructor() : Font { internal val JUNG_COUNT = 21 internal val JONG_COUNT = 28 - internal val W_CJK = 10 + internal val W_ASIAN_PUNCT = 10 + internal val W_HANGUL = 11 + internal val W_KANA = 12 internal val W_UNIHAN = 16 internal val W_LATIN_WIDE = 9 // width of regular letters, including m internal val W_LATIN_NARROW = 5 // width of letter f, t, i, l + internal val H = 20 internal val H_HANGUL = 16 internal val H_UNIHAN = 16 diff --git a/src/net/torvald/imagefont/GameFontWhite.kt b/src/net/torvald/imagefont/GameFontWhite.kt index aba08f639..ea6f2be4a 100644 --- a/src/net/torvald/imagefont/GameFontWhite.kt +++ b/src/net/torvald/imagefont/GameFontWhite.kt @@ -12,7 +12,7 @@ constructor() : GameFontBase() { init { GameFontBase.hangulSheet = SpriteSheet( - "./assets/graphics/fonts/han_johab.png", GameFontBase.W_CJK, GameFontBase.H_HANGUL) + "./assets/graphics/fonts/han_johab.png", GameFontBase.W_HANGUL, GameFontBase.H_HANGUL) GameFontBase.asciiSheet = SpriteSheet( "./assets/graphics/fonts/ascii_fullwidth.png", GameFontBase.W_LATIN_WIDE, GameFontBase.H) GameFontBase.asciiSheetEF = SpriteSheet( @@ -24,9 +24,9 @@ constructor() : GameFontBase() { GameFontBase.extASheetEF = SpriteSheet( "./assets/graphics/fonts/LatinExtA_ef.png", GameFontBase.W_LATIN_NARROW, GameFontBase.H) GameFontBase.kanaSheet = SpriteSheet( - "./assets/graphics/fonts/kana.png", GameFontBase.W_CJK, GameFontBase.H_KANA) + "./assets/graphics/fonts/kana.png", GameFontBase.W_KANA, GameFontBase.H_KANA) GameFontBase.cjkPunct = SpriteSheet( - "./assets/graphics/fonts/cjkpunct.png", GameFontBase.W_CJK, GameFontBase.H_KANA) + "./assets/graphics/fonts/cjkpunct.png", GameFontBase.W_ASIAN_PUNCT, GameFontBase.H_KANA) /*uniHan = new SpriteSheet( "./assets/graphics/fonts/unifont_unihan" + ((!terrarum.gameLocale.contains("zh")) diff --git a/src/net/torvald/terrarum/DefaultConfig.kt b/src/net/torvald/terrarum/DefaultConfig.kt index 9cdf62580..6b754364d 100644 --- a/src/net/torvald/terrarum/DefaultConfig.kt +++ b/src/net/torvald/terrarum/DefaultConfig.kt @@ -58,6 +58,8 @@ object DefaultConfig { jsonObject.addProperty("pcgamepadenv", "console") + jsonObject.addProperty("safetywarning", true) + return jsonObject } diff --git a/src/net/torvald/terrarum/StateFontTester.kt b/src/net/torvald/terrarum/StateFontTester.kt index 179b18a15..8be5f5ff7 100644 --- a/src/net/torvald/terrarum/StateFontTester.kt +++ b/src/net/torvald/terrarum/StateFontTester.kt @@ -1,6 +1,7 @@ package net.torvald.terrarum import net.torvald.imagefont.GameFontWhite +import net.torvald.terrarum.langpack.Lang import org.newdawn.slick.Font import org.newdawn.slick.GameContainer import org.newdawn.slick.Graphics @@ -20,6 +21,8 @@ class StateFontTester : BasicGameState() { canvas = Graphics(1024, 1024) gameFont = GameFontWhite() + + Terrarum.gameLocale = "fiFI" } override fun update(gc: GameContainer, game: StateBasedGame, delta: Int) { @@ -28,7 +31,21 @@ class StateFontTester : BasicGameState() { override fun render(gc: GameContainer, game: StateBasedGame, g: Graphics) { g.font = gameFont - g.drawString(textToPrint, 10f, 10f) + + val text = arrayOf( + Lang["APP_WARNING_HEALTH_AND_SAFETY"], + "", + "90’ 10’ 20” 50 cm", + "", + "", + Lang["MENU_LABEL_PRESS_ANYKEY_CONTINUE"], + "DGB금융지주의 자회사. 대구광역시에서 쓰는 교통카드인 원패스와 탑패스 그리고 만악의 근원 대경교통카드를 판매 및 정산하고 있다. 본사는", + "Atlantic Records, it features production from Nick Hexum of 311, Tony Kanal of No Doubt, and Sublime producer Paul Leary." + ) + + for (i in 0..text.size - 1) { + g.drawString(text[i], 10f, 10f + (g.font.lineHeight * i)) + } } override fun getID(): Int = Terrarum.SCENE_ID_TEST_FONT diff --git a/src/net/torvald/terrarum/StateInGame.kt b/src/net/torvald/terrarum/StateInGame.kt index e72caa8fc..c51894eb8 100644 --- a/src/net/torvald/terrarum/StateInGame.kt +++ b/src/net/torvald/terrarum/StateInGame.kt @@ -11,6 +11,7 @@ import net.torvald.terrarum.gamecontroller.Key import net.torvald.terrarum.gamecontroller.KeyMap import net.torvald.terrarum.gamecontroller.KeyToggler import net.torvald.terrarum.gamemap.GameWorld +import net.torvald.terrarum.gamemap.WorldSimulator import net.torvald.terrarum.gamemap.WorldTime import net.torvald.terrarum.mapdrawer.LightmapRenderer import net.torvald.terrarum.mapdrawer.MapCamera @@ -161,38 +162,56 @@ constructor() : BasicGameState() { setAppTitle() + /////////////////////////// + // world-related updates // + /////////////////////////// world.updateWorldTime(delta) - + WorldSimulator(world, player, delta) WeatherMixer.update(gc, delta) - world.globalLight = globalLightByTime.toInt() + + /////////////////////////// + // input-related updates // + /////////////////////////// GameController.processInput(gc.input) uiContainer.forEach { it.processInput(gc.input) } + TileStats.update() + + //////////////////////////// + // camera-related updates // + //////////////////////////// MapDrawer.update(gc, delta) MapCamera.update(gc, delta) + + /////////////////////////// + // actor-related updates // + /////////////////////////// // determine whether the inactive actor should be re-active wakeDormantActors() - // determine whether the actor should be active or dormant InactivateDistantActors() - updateActors(gc, delta) - // TODO thread pool(?) CollisionSolver.process() + + //////////////////////// + // ui-related updates // + //////////////////////// uiContainer.forEach { ui -> ui.update(gc, delta) } consoleHandler.update(gc, delta) debugWindow.update(gc, delta) - - notifier.update(gc, delta) + + ///////////////////////// + // app-related updates // + ///////////////////////// Terrarum.appgc.setVSync(Terrarum.appgc.fps >= Terrarum.VSYNC_TRIGGER_THRESHOLD) } @@ -204,8 +223,6 @@ constructor() : BasicGameState() { } override fun render(gc: GameContainer, sbg: StateBasedGame, g: Graphics) { - g.setAntiAlias(true) - setBlendNormal() // determine if lightmap blending should be done diff --git a/src/net/torvald/terrarum/StateMonitorCheck.kt b/src/net/torvald/terrarum/StateMonitorCheck.kt index 80610f6ec..18055aff4 100644 --- a/src/net/torvald/terrarum/StateMonitorCheck.kt +++ b/src/net/torvald/terrarum/StateMonitorCheck.kt @@ -1,7 +1,7 @@ package net.torvald.terrarum import net.torvald.terrarum.langpack.Lang -import net.torvald.terrarum.ui.Typesetter +import net.torvald.terrarum.ui.Typography import net.torvald.terrarum.ui.UICanvas import net.torvald.terrarum.ui.UIHandler import net.torvald.terrarum.ui.KeyboardControlled @@ -113,24 +113,24 @@ class StateMonitorCheck : BasicGameState() { // labels g.color = Color.white - Typesetter.printCentered( - Lang["MENU_MONITOR_CALI_TITLE"], + Typography.printCentered( + g, Lang["MENU_MONITOR_CALI_TITLE"], titleY, - this, g + this ) (1..12).forEach { - Typesetter.printCentered( - Lang["MENU_MONITOR_CALI_LABEL_$it"], + Typography.printCentered( + g, Lang["MENU_MONITOR_CALI_LABEL_$it"], instructionY + it.minus(2).times(g.font.lineHeight), - this, g + this ) } - Typesetter.printCentered( - Lang["MENU_LABEL_PRESS_ANYKEY_CONTINUE"], + Typography.printCentered( + g, Lang["MENU_LABEL_PRESS_ANYKEY_CONTINUE"], anykeyY, - this, g + this ) } diff --git a/src/net/torvald/terrarum/StateSplash.kt b/src/net/torvald/terrarum/StateSplash.kt new file mode 100644 index 000000000..a1e57980c --- /dev/null +++ b/src/net/torvald/terrarum/StateSplash.kt @@ -0,0 +1,139 @@ +package net.torvald.terrarum + +import com.jme3.math.FastMath +import net.torvald.terrarum.gameactors.roundInt +import net.torvald.terrarum.gamecontroller.Key +import net.torvald.terrarum.langpack.Lang +import net.torvald.terrarum.ui.DrawUtil +import net.torvald.terrarum.ui.Typography +import org.newdawn.slick.Color +import org.newdawn.slick.GameContainer +import org.newdawn.slick.Graphics +import org.newdawn.slick.Image +import org.newdawn.slick.state.BasicGameState +import org.newdawn.slick.state.StateBasedGame +import java.util.* + +/** + * Created by minjaesong on 16-08-04. + */ +class StateSplash : BasicGameState() { + + val pictogramCollection = ArrayList() + + val virtualImageHeight = 100 + var imageBoardHeight = 0 + var imageBoardOffset = 0 + + lateinit var fadeSheet: Image + lateinit var thisG: Graphics + + var opacity = 0f + + val fadeTime = 500 + var fadeTimer = 0 + + var anykey_hit = false + + val backgroundColour = Color(0x303030) + + var delta = 0 + val deltathre = 500 + + val auto_dismiss = 5000 + + var opened = false + + override fun init(container: GameContainer?, game: StateBasedGame?) { + // pre-load lang + Lang["MENU_LANGUAGE_THIS"] + + pictogramCollection.add(Image("./assets/graphics/gui/health_take_a_break.png")) + pictogramCollection.add(Image("./assets/graphics/gui/health_distance.png")) + + fadeSheet = Image(Terrarum.WIDTH, Terrarum.HEIGHT) + thisG = fadeSheet.graphics + thisG.font = Terrarum.gameFont + } + + override fun update(container: GameContainer, game: StateBasedGame, delta: Int) { + this.delta = delta + + // next splash or load next scene + if (anykey_hit && opacity == 0f) { + System.exit(0) + } + + // fade-in + if (delta < deltathre) { + if (opacity < 1f && !anykey_hit) { + opacity = FastMath.interpolateLinear( + fadeTimer.toFloat() / fadeTime, 0f, 1f + ) + } + else if (opacity > 0f && anykey_hit) { + opacity = FastMath.interpolateLinear( + fadeTimer.toFloat() / fadeTime, 1f, 0f + ) + } + + if (!opened && fadeTimer >= fadeTime && !anykey_hit) { + fadeTimer = 0 + opened = true + } + } + + // auto dismiss + if (opened && fadeTimer >= auto_dismiss) + doAnykeyThingy() + + fadeTimer += delta + } + + override fun getID(): Int = Terrarum.SCENE_ID_SPLASH + + override fun render(container: GameContainer?, game: StateBasedGame?, g: Graphics) { + + imageBoardHeight = Terrarum.HEIGHT - thisG.font.lineHeight.times(6) + imageBoardOffset = thisG.font.lineHeight.times(3) + + thisG.color = backgroundColour + thisG.fillRect(0f, 0f, fadeSheet.width.toFloat(), fadeSheet.height.toFloat()) + + thisG.color = Color.white + + Typography.printCentered(thisG, Lang["APP_WARNING_HEALTH_AND_SAFETY"], + thisG.font.lineHeight * 2) + + Typography.printCentered(thisG, Lang["MENU_LABEL_PRESS_ANYKEY_CONTINUE"], + Terrarum.HEIGHT - thisG.font.lineHeight.times(3)) + + pictogramCollection.forEachIndexed { i, image -> + DrawUtil.drawCentered(thisG, image, knowYourPlace(i) + imageBoardOffset) + } + + g.drawImage(fadeSheet, 0f, 0f, Color(1f, 1f, 1f, opacity)) + } + + private fun knowYourPlace(i: Int): Int { + val gutter = (imageBoardHeight - virtualImageHeight.times(pictogramCollection.size)).toFloat().div( + pictogramCollection.size + 1f + ) + return (gutter * i.plus(1) + virtualImageHeight * i).roundInt() + } + + override fun keyPressed(key: Int, c: Char) { + doAnykeyThingy() + } + + override fun controllerButtonPressed(controller: Int, button: Int) { + doAnykeyThingy() + } + + private fun doAnykeyThingy() { + if (delta < deltathre && !anykey_hit) { + anykey_hit = true + fadeTimer = 0 + } + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index b87c0a13a..006b296dd 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -73,9 +73,13 @@ constructor(gamename: String) : StateBasedGame(gamename) { } } + gc.graphics.clear() // clean up any 'dust' in the buffer + ingame = StateInGame() //addState(ingame) - addState(StateMonitorCheck()) + //addState(StateMonitorCheck()) + //addState(StateFontTester()) + addState(StateSplash()) } companion object { @@ -103,8 +107,8 @@ constructor(gamename: String) : StateBasedGame(gamename) { lateinit var appgc: AppGameContainer - val WIDTH = 1072 - val HEIGHT = 742 // IMAX ratio + var WIDTH = 1072 + var HEIGHT = 742 // IMAX ratio var VSYNC = true val VSYNC_TRIGGER_THRESHOLD = 56 @@ -141,6 +145,7 @@ constructor(gamename: String) : StateBasedGame(gamename) { // 0x0 - 0xF: Game-related // 0x10 - 0x1F: Config // 0x100 and onward: unit tests for dev + val SCENE_ID_SPLASH = 0x0 val SCENE_ID_HOME = 0x1 val SCENE_ID_GAME = 0x3 val SCENE_ID_CONFIG_CALIBRATE = 0x11 @@ -362,7 +367,7 @@ fun main(args: Array) = Terrarum.main(args) fun setBlendMul() { GL11.glEnable(GL11.GL_BLEND) - GL11.glColorMask(true, true, true, true) + GL11.glColorMask(true, true, true, false) GL11.glBlendFunc(GL11.GL_DST_COLOR, GL11.GL_ONE_MINUS_SRC_ALPHA) } diff --git a/src/net/torvald/terrarum/gameactors/ActorWithBody.kt b/src/net/torvald/terrarum/gameactors/ActorWithBody.kt index bd4586951..be3b4421b 100644 --- a/src/net/torvald/terrarum/gameactors/ActorWithBody.kt +++ b/src/net/torvald/terrarum/gameactors/ActorWithBody.kt @@ -1,5 +1,6 @@ package net.torvald.terrarum.gameactors +import com.jme3.math.FastMath import net.torvald.terrarum.* import net.torvald.terrarum.gamemap.GameWorld import net.torvald.terrarum.mapdrawer.MapDrawer @@ -971,10 +972,12 @@ open class ActorWithBody : Actor(), Visible { } fun Double.floorInt() = Math.floor(this).toInt() +fun Float.floorInt() = FastMath.floor(this).toInt() fun Double.round() = Math.round(this).toDouble() fun Double.floor() = Math.floor(this) fun Double.ceil() = this.floor() + 1.0 fun Double.roundInt(): Int = Math.round(this).toInt() +fun Float.roundInt(): Int = Math.round(this).toInt() fun Double.abs() = Math.abs(this) fun Double.sqr() = this * this fun Int.abs() = if (this < 0) -this else this diff --git a/src/net/torvald/terrarum/gameactors/MDLInterpreterState.kt b/src/net/torvald/terrarum/gameactors/MDLInterpreterState.kt index 08e46aa07..99eebdc7a 100644 --- a/src/net/torvald/terrarum/gameactors/MDLInterpreterState.kt +++ b/src/net/torvald/terrarum/gameactors/MDLInterpreterState.kt @@ -46,27 +46,6 @@ class MDLInterpreterState { // push, pop, +, -, *, /, %, dup, swap, drop } - class MagicOrInt() { - private var magic: MagicWords? = null - private var number: Int? = null - - constructor(kynngi: MagicWords): this() { - magic = kynngi - } - - constructor(integer: Int) : this() { - number = integer - } - - fun toMagic() = if (magic != null) magic!! else throw TypeCastException("$this: cannot be cast to MagicWord") - fun toInt() = if (number != null) number!! else throw TypeCastException("$this: cannot be cast to MagicWord") - - fun isMagic() = (magic != null) - fun isInt() = (number != null) - - override fun toString(): String = if (magic != null && number == null) "$magic" else if (magic == null && number != null) "$number" else "INVALID" - } - class MagicArrayStack { /** * Number of elements in the stack @@ -81,28 +60,28 @@ class MDLInterpreterState { else deflate(data.size - newSize) } - private lateinit var data: Array + private lateinit var data: Array constructor(stackSize: Int) { data = Array(stackSize, { null }) } - constructor(arr: Array) { + constructor(arr: Array) { data = arr.copyOf() depth = size } - fun push(v: MagicOrInt) { + fun push(v: Int) { if (depth >= data.size) throw StackOverflowError() data[depth++] = v } - fun pop(): MagicOrInt { + fun pop(): Int { if (depth == 0) throw EmptyStackException() return data[--depth]!! } - fun peek(): MagicOrInt? { + fun peek(): Int? { if (depth == 0) return null return data[depth - 1] } @@ -126,7 +105,7 @@ class MDLInterpreterState { --depth } - fun defineFromArray(arr: Array) { data = arr.copyOf() } + fun defineFromArray(arr: Array) { data = arr.copyOf() } /** * Increase the stack size by a factor. @@ -157,10 +136,10 @@ class MDLInterpreterState { fun equalTo(other: MagicArrayStack) = (this.asArray() == other.asArray()) - fun plus() { if (data[depth - 2]!!.isInt() && peek()!!.isInt()) data[depth - 2] = MagicOrInt(data[depth - 2]!!.toInt() + (pop().toInt())) else throw RuntimeException("${data[depth - 2]}: Cannot do arithmetic operation on non-numeric type.") } - fun minus() { if (data[depth - 2]!!.isInt() && peek()!!.isInt()) data[depth - 2] = MagicOrInt(data[depth - 2]!!.toInt() - (pop().toInt())) else throw RuntimeException("${data[depth - 2]}: Cannot do arithmetic operation on non-numeric type.") } - fun times() { if (data[depth - 2]!!.isInt() && peek()!!.isInt()) data[depth - 2] = MagicOrInt(data[depth - 2]!!.toInt() * (pop().toInt())) else throw RuntimeException("${data[depth - 2]}: Cannot do arithmetic operation on non-numeric type.") } - fun div() { if (data[depth - 2]!!.isInt() && peek()!!.isInt()) data[depth - 2] = MagicOrInt(data[depth - 2]!!.toInt() / (pop().toInt())) else throw RuntimeException("${data[depth - 2]}: Cannot do arithmetic operation on non-numeric type.") } - fun mod() { if (data[depth - 2]!!.isInt() && peek()!!.isInt()) data[depth - 2] = MagicOrInt(data[depth - 2]!!.toInt() % (pop().toInt())) else throw RuntimeException("${data[depth - 2]}: Cannot do arithmetic operation on non-numeric type.") } + fun plus() { data[depth - 2] = data[depth - 2]!! + (pop().toInt()) } + fun minus() { data[depth - 2] = data[depth - 2]!! - (pop().toInt()) } + fun times() { data[depth - 2] = data[depth - 2]!! * (pop().toInt()) } + fun div() { data[depth - 2] = data[depth - 2]!! / (pop().toInt()) } + fun mod() { data[depth - 2] = data[depth - 2]!! % (pop().toInt()) } } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/gamemap/GameWorld.kt b/src/net/torvald/terrarum/gamemap/GameWorld.kt index ebcc638d2..4a6c4f05a 100644 --- a/src/net/torvald/terrarum/gamemap/GameWorld.kt +++ b/src/net/torvald/terrarum/gamemap/GameWorld.kt @@ -1,6 +1,9 @@ package net.torvald.terrarum.gamemap +import net.torvald.terrarum.gameactors.Player +import net.torvald.terrarum.gameactors.roundInt +import net.torvald.terrarum.mapdrawer.MapDrawer import org.dyn4j.geometry.Vector2 import org.newdawn.slick.SlickException diff --git a/src/net/torvald/terrarum/gamemap/MapLayer.kt b/src/net/torvald/terrarum/gamemap/MapLayer.kt index ae6599e4c..ab3883243 100644 --- a/src/net/torvald/terrarum/gamemap/MapLayer.kt +++ b/src/net/torvald/terrarum/gamemap/MapLayer.kt @@ -47,6 +47,8 @@ class MapLayer(var width: Int, var height: Int) : Iterable { data[y][x] = tile } + fun isInBound(x: Int, y: Int) = (x >= 0 && y >= 0 && x < width && y < height) + private fun uint8ToInt32(x: Byte): Int = java.lang.Byte.toUnsignedInt(x) companion object { diff --git a/src/net/torvald/terrarum/gamemap/WorldSimulator.kt b/src/net/torvald/terrarum/gamemap/WorldSimulator.kt new file mode 100644 index 000000000..26b27028f --- /dev/null +++ b/src/net/torvald/terrarum/gamemap/WorldSimulator.kt @@ -0,0 +1,188 @@ +package net.torvald.terrarum.gamemap + +import net.torvald.random.HQRNG +import net.torvald.terrarum.gameactors.Player +import net.torvald.terrarum.gameactors.roundInt +import net.torvald.terrarum.mapdrawer.MapDrawer +import net.torvald.terrarum.tileproperties.TileNameCode +import net.torvald.terrarum.tileproperties.TilePropCodex +import org.newdawn.slick.Graphics + +/** + * Created by minjaesong on 16-08-03. + */ +object WorldSimulator { + /** + * In tiles; + * square width/height = field * 2 + */ + const val FLUID_UPDATING_SQUARE_RADIUS = 128 + const private val DOUBLE_RADIUS = FLUID_UPDATING_SQUARE_RADIUS * 2 + + private val fluidMap = Array(DOUBLE_RADIUS, { IntArray(DOUBLE_RADIUS) }) + + const val DISPLACE_CAP = 4 + const val FLUID_MAX = 16 + + operator fun invoke(world: GameWorld, p: Player, delta: Int) { + moveFluids(world, p, delta) + } + + /** + * displace fluids. Note that the code assumes the gravity pulls things downward ONLY, + * which means you'll need to modify the code A LOT if you're going to implement zero- or + * reverse-gravity. + */ + fun moveFluids(world: GameWorld, p: Player, delta: Int) { + val updateXFrom = p.hitbox.centeredX.div(MapDrawer.TILE_SIZE).minus(FLUID_UPDATING_SQUARE_RADIUS).roundInt() + val updateYFrom = p.hitbox.centeredY.div(MapDrawer.TILE_SIZE).minus(FLUID_UPDATING_SQUARE_RADIUS).roundInt() + val updateXTo = updateXFrom + 1 * FLUID_UPDATING_SQUARE_RADIUS + val updateYTo = updateYFrom + 1 * FLUID_UPDATING_SQUARE_RADIUS + + /** + * @return amount of fluid actually drained. + * (intended drainage - this) will give you how much fluid is not yet drained. + */ + fun drain(x: Int, y: Int, amount: Int): Int { + val displacement = Math.min(fluidMap[y - updateYFrom][x - updateXFrom], amount) + + fluidMap[y - updateYFrom][x - updateXFrom] -= displacement + + return displacement + } + + fun pour(x: Int, y: Int, amount: Int) { + fun pourInternal(xpos: Int, ypos: Int, volume: Int): Int { + var spil = 0 + + val addrX = xpos - updateXFrom + val addrY = ypos - updateYFrom + + if (addrX >= 0 && addrY >= 0 && addrX < DOUBLE_RADIUS && addrY < DOUBLE_RADIUS) { + fluidMap[addrY][addrX] += volume + if (fluidMap[addrY][addrX] > FLUID_MAX) { + spil = fluidMap[addrY][addrX] - FLUID_MAX + fluidMap[addrY][addrX] = FLUID_MAX + } + } + + return spil + } + + // pour the fluid + var spillage = pourInternal(x, y, amount) + + if (spillage == 0) return + + // deal with the spillage + + val tileUp = world.getTileFromTerrain(x - updateXFrom, y - updateYFrom - 1) + val tileDown = world.getTileFromTerrain(x - updateXFrom, y - updateYFrom + 1) + + // try to fill downward + if (tileDown != null && !tileDown.isSolid()) { + spillage = pourInternal(x, y + 1, spillage) + } + // else, try to fill upward. if there is no space, just discard + if (tileUp != null && !tileUp.isSolid()) { + pourInternal(x, y - 1, spillage) + } + } + + purgeFluidMap() + + ///////////////////////////////////////////////////////////// + // displace fluids. Record displacements into the fluidMap // + ///////////////////////////////////////////////////////////// + for (y in updateYFrom..updateYTo) { + for (x in updateXFrom..updateXTo) { + val tile = world.getTileFromTerrain(x, y) + val tileBottom = world.getTileFromTerrain(x, y + 1) + val tileLeft = world.getTileFromTerrain(x - 1, y) + val tileRight = world.getTileFromTerrain(x + 1, y) + if (tile != null && tile.isFluid()) { + + // move down if not obstructed + if (tileBottom != null && !tileBottom.isSolid()) { + val drainage = drain(x, y, DISPLACE_CAP) + pour(x, y + 1, drainage) + } + // left and right both open (null is considered as open) + else if ((tileLeft != null && tileRight != null && !tileLeft.isSolid() && !tileRight.isSolid()) || + tileLeft == null && tileRight == null) { + // half-breaker + val moreToTheRight = HQRNG().nextBoolean() + val displacement = drain(x, y, DISPLACE_CAP) + + if (displacement.isEven()) { + pour(x - 1, y, displacement shr 1) + pour(x + 1, y, displacement shr 1) + } + else { + pour(x - 1, y, (displacement shr 1) + if (moreToTheRight) 0 else 1) + pour(x + 1, y, (displacement shr 1) + if (moreToTheRight) 1 else 0) + } + } + // left open (null is considered as open) + else if ((tileLeft != null && !tileLeft.isSolid()) || tileLeft == null) { + val displacement = drain(x, y, DISPLACE_CAP) + pour(x - 1, y, displacement) + } + // right open (null is considered as open) + else if ((tileRight != null && !tileRight.isSolid()) || tileRight == null) { + val displacement = drain(x, y, DISPLACE_CAP) + pour(x + 1, y, displacement) + } + // nowhere open; do default (fill top) + else { + pour(x, y - 1, DISPLACE_CAP) + } + } + } + } + ///////////////////////////////////////////////////// + // replace fluids in the map according to fluidMap // + ///////////////////////////////////////////////////// + for (y in 0..fluidMap.size - 1) { + for (x in 0..fluidMap[0].size - 1) { + placeFluid(world, updateXFrom + x, updateYFrom + y, WATER, fluidMap[y][x].minus(1)) + // FIXME test code: deals with water only! + } + } + + } + + fun drawFluidMapDebug(p: Player, g: Graphics) { + for (y in 0..fluidMap.size - 1) { + for (x in 0..fluidMap[0].size - 1) { + + } + } + } + + private fun purgeFluidMap() { + for (y in 1..DOUBLE_RADIUS) + for (x in 1..DOUBLE_RADIUS) + fluidMap[y - 1][x - 1] = 0 + } + + fun Int.isFluid() = TilePropCodex.getProp(this).isFluid + fun Int.isSolid() = TilePropCodex.getProp(this).isSolid + //fun Int.viscosity() = TilePropCodex.getProp(this). + fun Int.fluidLevel() = this % FLUID_MAX + fun Int.isEven() = (this and 0x01) == 0 + + private fun placeFluid(world: GameWorld, x: Int, y: Int, tileFluid: Int, amount: Int) { + if (world.layerTerrain.isInBound(x, y)) { + if (amount > 0 && !world.getTileFromTerrain(x, y)!!.isSolid()) { + world.setTileTerrain(x, y, amount.minus(1).plus(tileFluid)) + } + else if (amount == 0 && world.getTileFromTerrain(x, y)!!.isFluid()) { + world.setTileTerrain(x, y, TileNameCode.AIR) + } + } + } + + val LAVA = TileNameCode.LAVA_1 + val WATER = TileNameCode.WATER_1 +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/mapdrawer/MapCamera.kt b/src/net/torvald/terrarum/mapdrawer/MapCamera.kt index d930ab85b..581d19b02 100644 --- a/src/net/torvald/terrarum/mapdrawer/MapCamera.kt +++ b/src/net/torvald/terrarum/mapdrawer/MapCamera.kt @@ -381,7 +381,8 @@ object MapCamera { var ret = 0 for (i in 0..3) { try { - if (!TilePropCodex.getProp(nearbyTiles[i]).isSolid) { + if (!TilePropCodex.getProp(nearbyTiles[i]).isSolid && + !TilePropCodex.getProp(nearbyTiles[i]).isFluid) { ret += (1 shl i) // add 1, 2, 4, 8 for i = 0, 1, 2, 3 } } catch (e: ArrayIndexOutOfBoundsException) { diff --git a/src/net/torvald/terrarum/tileproperties/tileprop.csv b/src/net/torvald/terrarum/tileproperties/tileprop.csv index 2f04cd5c8..02bea2db9 100644 --- a/src/net/torvald/terrarum/tileproperties/tileprop.csv +++ b/src/net/torvald/terrarum/tileproperties/tileprop.csv @@ -1,5 +1,5 @@ "id";"dmg";"name" ; "opacity";"strength";"dsty";"fluid";"solid";"wall"; "lumcolor";"drop";"ddmg";"fall";"dlfn";"friction" - "0"; "0";"TILE_AIR" ; "8396808"; "0"; "1"; "1"; "0"; "0"; "0"; "0"; "0"; "0"; "0";"4" + "0"; "0";"TILE_AIR" ; "8396808"; "0"; "1"; "0"; "0"; "0"; "0"; "0"; "0"; "0"; "0";"4" "1"; "0";"TILE_STONE" ; "33587232"; "25";"2400"; "0"; "1"; "1"; "0"; "1"; "0"; "0"; "0";"16" "1"; "1";"TILE_STONE_QUARRIED" ; "33587232"; "25";"2400"; "0"; "1"; "1"; "0"; "1"; "1"; "0"; "0";"16" "1"; "2";"TILE_STONE_TILE_WHITE" ; "33587232"; "25";"2400"; "0"; "1"; "1"; "0"; "1"; "2"; "0"; "0";"16" diff --git a/src/net/torvald/terrarum/ui/DrawUtil.kt b/src/net/torvald/terrarum/ui/DrawUtil.kt new file mode 100644 index 000000000..09b2018a5 --- /dev/null +++ b/src/net/torvald/terrarum/ui/DrawUtil.kt @@ -0,0 +1,17 @@ +package net.torvald.terrarum.ui + +import net.torvald.terrarum.Terrarum +import org.newdawn.slick.Graphics +import org.newdawn.slick.Image + +/** + * Created by minjaesong on 16-08-04. + */ +object DrawUtil { + fun drawCentered(g: Graphics, image: Image, screenPosY: Int, ui: UICanvas? = null) { + val imageW = image.width + val targetW = if (ui == null) Terrarum.WIDTH else ui.width + + g.drawImage(image, targetW.minus(imageW).ushr(1).toFloat(), screenPosY.toFloat()) + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/ui/Typesetter.kt b/src/net/torvald/terrarum/ui/Typography.kt similarity index 54% rename from src/net/torvald/terrarum/ui/Typesetter.kt rename to src/net/torvald/terrarum/ui/Typography.kt index 147bdf13d..3236dcc7d 100644 --- a/src/net/torvald/terrarum/ui/Typesetter.kt +++ b/src/net/torvald/terrarum/ui/Typography.kt @@ -1,14 +1,15 @@ package net.torvald.terrarum.ui +import net.torvald.terrarum.Terrarum import org.newdawn.slick.Graphics /** * Created by minjaesong on 16-07-06. */ -object Typesetter { - fun printCentered(string: String, screenPosY: Int, ui: UICanvas, g: Graphics) { +object Typography { + fun printCentered(g: Graphics, string: String, screenPosY: Int, ui: UICanvas? = null) { val stringW = g.font.getWidth(string) - val targetW = ui.width + val targetW = if (ui == null) Terrarum.WIDTH else ui.width g.drawString(string, targetW.minus(stringW).ushr(1).toFloat(), screenPosY.toFloat()) } diff --git a/src/net/torvald/terrarum/weather/BaseModularWeather.kt b/src/net/torvald/terrarum/weather/BaseModularWeather.kt index 71dd0dfd5..0e6a88777 100644 --- a/src/net/torvald/terrarum/weather/BaseModularWeather.kt +++ b/src/net/torvald/terrarum/weather/BaseModularWeather.kt @@ -14,5 +14,7 @@ data class BaseModularWeather( val globalLightColourMap: Image, var skyboxGradColourMap: Image, val classification: String, - var extraImages: ArrayList + var extraImages: ArrayList, + val mixFrom: String? = null, + val mixPercentage: Double? = null ) \ No newline at end of file diff --git a/src/net/torvald/terrarum/weather/WeatherMixer.kt b/src/net/torvald/terrarum/weather/WeatherMixer.kt index ebf522aef..8cd9e3bfe 100644 --- a/src/net/torvald/terrarum/weather/WeatherMixer.kt +++ b/src/net/torvald/terrarum/weather/WeatherMixer.kt @@ -27,12 +27,15 @@ object WeatherMixer { lateinit var currentWeather: BaseModularWeather lateinit var nextWeather: BaseModularWeather + lateinit var mixedWeather: 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 = "generic" + const val WEATHER_GENERIC_RAIN = "genericrain" // TODO add weather classification indices manually const val RAW_DIR = "./assets/raw/weathers" @@ -169,6 +172,12 @@ object WeatherMixer { val skybox: Image val extraImages = ArrayList() val classification = JSON.get("classification").asJsonPrimitive.asString + val mixFrom: String? + try { mixFrom = JSON.get("mixFrom").asJsonPrimitive.asString } + catch (e: NullPointerException) { mixFrom = null } + val mixPercentage: Double? + try { mixPercentage = JSON.get("mixPercentage").asJsonPrimitive.asDouble } + catch (e: NullPointerException) { mixPercentage = null } // parse globalLight if (globalLightInJson.isString) @@ -196,7 +205,10 @@ object WeatherMixer { // get extra images for (i in extraImagesPath) - extraImages.add(Image("$pathToImage/$i")) + extraImages.add(Image("$pathToImage/${i.asString}")) + + // get mix from + return BaseModularWeather(globalLight, skybox, classification, extraImages) } diff --git a/work_files/health_and_safety.tiff b/work_files/health_and_safety.tiff new file mode 100644 index 000000000..9fff3fedd Binary files /dev/null and b/work_files/health_and_safety.tiff differ diff --git a/work_files/magic_description_language.numbers b/work_files/magic_description_language.numbers index 15c2065ce..8d67af500 100644 Binary files a/work_files/magic_description_language.numbers and b/work_files/magic_description_language.numbers differ