cavegen renewed (WIP)

Former-commit-id: c29114d50d7d86ef903aa2215b5603a01547999a
Former-commit-id: 1099816bc5fd8998cbd538a855c9986bc6b1b983
This commit is contained in:
Song Minjae
2016-04-01 14:38:45 +09:00
parent aa914377fe
commit 1573851130
22 changed files with 528 additions and 731 deletions

View File

@@ -8,6 +8,6 @@
"DEV_COLOUR_LEGEND_ORANGE";;"ORANGE";"ORANGE";;;;;;;;;;;;;;;"黄";;;"황";;;;;;;"オレンジ";"rauðugulur"
"DEV_COLOUR_LEGEND_RED";;" RED";" ROUGE";;;;;;;;;;;;;;;"赤";;;"적";;;;;;;"  あか";"rauður"
"DEV_MESSAGE_CONSOLE_CODEX";;"Type “codex” for available commands.";"Tapez « codex » pour commandes disponibles.";;;;;;;;;;;;;;;"使用可能な命令語の目録は「codex」を入力してさい。";;;"사용 가능한 명령어 목록을 보려면 codex를 입력해 주십시오.";;;;;;;"しよう かのうな めいれいごの もくろくは 「codex」を にゅうりょく して ください。";"Skrifa „codex“ fyrir tiltækilegum skipunum."
"DEV_MESSAGE_CONSOLE_CODEX";;"Type “codex” for available commands.";"Tapez « codex » pour commandes disponibles.";;;;;;;;;;;;;;;"使用可能な命令語の目録は「codex」を入力してください。";;;"사용 가능한 명령어 목록을 보려면 codex를 입력해 주십시오.";;;;;;;"しようかのうな めいれいごのもくろくは 「codex」を にゅうりょくしてください。";"Skrifa „codex“ fyrir tiltækilegum skipunum."
"DEV_MESSAGE_CONSOLE_AVAILABLE_COMMANDS";;"Available commends:";"Commandes disponibles :";;;;;;;;;;;;;;;"命令語の目録:";;;"명령어 목록:";;;;;;;"めいれいごの もくろく:";"Listi skipana :"
"DEV_MESSAGE_CONSOLE_COMMAND_UNKNOWN";;"“%1$s”: Unknown command";"« %1$s » : Commande inconnue";;;;;;;;;;;;;;;"「%1$s」: 不明な命令語";;;"%1$s: 알 수 없는 명령어";;;;;;;"「%1$s」: ふめいな めいれいご";"„%1$s“ : óþekkt skipunin"
1 STRING_ID IETF language tag(s) without dash enUS frFR esES deDE itIT ptBR ptPT ruRU elGR trTR daDK noNB svSE nlNL plPL fiFI jaJP zhCN zhTW koKR csCZ huHU roRO thTH bgBG heIL jakanaJP isIC
8 DEV_MESSAGE_CONSOLE_CODEX Type “codex” for available commands. Tapez « codex » pour commandes disponibles. 使用可能な命令語の目録は「codex」を入力して下さい。 使用可能な命令語の目録は「codex」を入力してください。 사용 가능한 명령어 목록을 보려면 ‘codex’를 입력해 주십시오. しよう かのうな めいれいごの もくろくは 「codex」を にゅうりょく して ください。 しようかのうな めいれいごのもくろくは 「codex」を にゅうりょくしてください。 Skrifa „codex“ fyrir tiltækilegum skipunum.
9 DEV_MESSAGE_CONSOLE_AVAILABLE_COMMANDS Available commends: Commandes disponibles : 命令語の目録: 명령어 목록: めいれいごの もくろく: Listi skipana :
10 DEV_MESSAGE_CONSOLE_COMMAND_UNKNOWN “%1$s”: Unknown command « %1$s » : Commande inconnue 「%1$s」: 不明な命令語 ‘%1$s’: 알 수 없는 명령어 「%1$s」: ふめいな めいれいご „%1$s“ : óþekkt skipunin
11
12
13

View File

@@ -1,14 +1,14 @@
"STRING_ID";"IETF language tag(s) without dash";"enUS";"frFR";"esES";"deDE";"itIT";"ptBR";"ptPT";"ruRU";"elGR";"trTR";"daDK";"noNB";"svSE";"nlNL";"plPL";"fiFI";"jaJP";"zhCN";"zhTW";"koKR";"csCZ";"huHU";"roRO";"thTH";"bgBG";"heIL";"jakanaJP";"isIC"
"HELP_OTF_MAIN_1";;"Type “help slow” for the ways to make the game run faster.";"Tapez « help slow » si votre jeu fonctionne lentement.";;;;;;;;;;;;;;;;;;"게임이 느리게 돌아간다면 “help slow”를 입력해 보세요."
"HELP_OTF_MAIN_2";;"Press PageUp/PageDown to scroll the messages.";"Appuyez sur PageUp/Pagedown pour faire défiler les messages.";;;;;;;;;;;;;;;;;;"PageUp/PageDown 키를 사용해 메시지를 스크롤할 수 있습니다."
"HELP_OTF_MAIN_2";;"Press PageUp/PageDown to scroll the messages.";"Appuyez sur PageUp/PageDown pour faire défiler les messages.";;;;;;;;;;;;;;;;;;"PageUp/PageDown 키를 사용해 메시지를 스크롤할 수 있습니다."
"HELP_OTF_MAIN_3";;"Utility keys:";"Touches utilitaires:";;;;;;;;;;;;;;;;;;"기능 키:"
"HELP_OTF_MAIN_4";;"• F3: basic information";"• F3: informations de base";;;;;;;;;;;;;;;;;;"• F3: 기본 정보"
"HELP_OTF_MAIN_5";;"• F7: (debug) toggle light blending";"• F7: (déboguer) basculer fusion de lumière";;;;;;;;;;;;;;;;;;"• F7: (디버그용) 광원 블렌딩 켜고 끄기"
"HELP_OTF_MAIN_6";;"• F8: toggle smooth lighting";"• F8: basculer éclairage lisse";;;;;;;;;;;;;;;;;;"• F8: 부드러운 광원 켜고 끄기"
"HELP_OTF_SLOW_1";;"To make your game run faster:";"Pour rendre votre jeu courir plus vite :";;;;;;;;;;;;;;;;;;"게임을 빠르게 하려면"
"HELP_OTF_SLOW_IF_ZOOM";;"• Reset screen zoom to 1.";"• Réinitialisez le zoom de lécran à 1.";;;;;;;;;;;;;;;;;;"• 화면 줌을 1로 돌려주세요. "
"HELP_OTF_SLOW_IF_F3";;"• Turn off the basic information window.";"• Désactivez la fenêtre dinformations.";;;;;;;;;;;;;;;;;;"• 기본 정보 창을 꺼 주세요."
"HELP_OTF_SLOW_1";;"• Turn off smooth lighting. You can do it now by pressing F8.";"• Désactivez éclairage lisse en utilisant F8.";;;;;;;;;;;;;;;;;;"• 부드러운 광원 효과를 꺼 주세요. F8을 사용할 수 있습니다."
"HELP_OTF_SLOW_1";;"If your game runs slowly:";"Si votre jeu tourne lentement :";;;;;;;;;;;;;;;;;"";"게임이 느리게 돌아간다면"
"HELP_OTF_SLOW_2";;"• Reset screen zoom to 1.";"• Réinitialisez le zoom de lécran à 1.";;;;;;;;;;;;;;;;;;"• 화면 줌을 1로 돌려주세요. "
"HELP_OTF_SLOW_3";;"• Turn off the basic information window.";"• Désactivez la fenêtre dinformations.";;;;;;;;;;;;;;;;;;"• 기본 정보 창을 꺼 주세요."
"HELP_OTF_SLOW_4";;"• Turn off smooth lighting. You can do it now by pressing F8.";"• Désactivez éclairage lisse en utilisant F8.";;;;;;;;;;;;;;;;;;"• 부드러운 광원 효과를 꺼 주세요. F8을 사용할 수 있습니다."
1 STRING_ID IETF language tag(s) without dash enUS frFR esES deDE itIT ptBR ptPT ruRU elGR trTR daDK noNB svSE nlNL plPL fiFI jaJP zhCN zhTW koKR csCZ huHU roRO thTH bgBG heIL jakanaJP isIC
2 HELP_OTF_MAIN_1 Type “help slow” for the ways to make the game run faster. Tapez « help slow » si votre jeu fonctionne lentement. 게임이 느리게 돌아간다면 “help slow”를 입력해 보세요.
3 HELP_OTF_MAIN_2 Press PageUp/PageDown to scroll the messages. Appuyez sur PageUp/Pagedown pour faire défiler les messages. Appuyez sur PageUp/PageDown pour faire défiler les messages. PageUp/PageDown 키를 사용해 메시지를 스크롤할 수 있습니다.
4 HELP_OTF_MAIN_3 Utility keys: Touches utilitaires: 기능 키:
5 HELP_OTF_MAIN_4 • F3: basic information • F3: informations de base • F3: 기본 정보
6 HELP_OTF_MAIN_5 • F7: (debug) toggle light blending • F7: (déboguer) basculer fusion de lumière • F7: (디버그용) 광원 블렌딩 켜고 끄기
7 HELP_OTF_MAIN_6 • F8: toggle smooth lighting • F8: basculer éclairage lisse • F8: 부드러운 광원 켜고 끄기
8 HELP_OTF_SLOW_1 To make your game run faster: If your game runs slowly: Pour rendre votre jeu courir plus vite : Si votre jeu tourne lentement : 게임을 빠르게 하려면 게임이 느리게 돌아간다면
9 HELP_OTF_SLOW_IF_ZOOM HELP_OTF_SLOW_2 • Reset screen zoom to 1. • Réinitialisez le zoom de l‘écran à 1. • 화면 줌을 1로 돌려주세요.
10 HELP_OTF_SLOW_IF_F3 HELP_OTF_SLOW_3 • Turn off the basic information window. • Désactivez la fenêtre d‘informations. • 기본 정보 창을 꺼 주세요.
11 HELP_OTF_SLOW_1 HELP_OTF_SLOW_4 • Turn off smooth lighting. You can do it now by pressing F8. • Désactivez éclairage lisse en utilisant F8. • 부드러운 광원 효과를 꺼 주세요. F8을 사용할 수 있습니다.
12
13
14

View File

@@ -1,6 +1,6 @@
"STRING_ID";"IETF language tag(s) without dash";"enUS";"frFR";"esES";"deDE";"itIT";"ptBR";"ptPT";"ruRU";"elGR";"trTR";"daDK";"noNB";"svSE";"nlNL";"plPL";"fiFI";"jaJP";"zhCN";"zhTW";"koKR";"csCZ";"huHU";"roRO";"thTH";"bgBG";"heIL";"jakanaJP";"isIC"
"APP_CALIBRATE_YOUR_MONITOR";;"Best player experience can be achieved with properly calibrated monitor. If you have not, please do it before you play.";"Meilleure expérience de joueur peut être réalisé avec écran correctement calibré. Si vous ne l'avez pas, s.v.p. le calibrez avant de jouer.";;;;;;;;;;;;;;;"このゲームは、適切に調整したモニターから最高のプレイができます。調整していなかったら、プレイする前に調整してさい。";;;"본 게임은 적절히 보정된 모니터에서 최상으로 즐길 수 있습니다. 보정하지 않았다면 플레이하기 전에 보정해 주십시오.";;;;;;;"このゲームは てきせつに ちょうせいしたモニターから さいこうのプレイができます。ちょうせいして いなかったら プレイするまえに ちょうせいしてください。";"Best leikmaður reynsla er getur náðist með rétt kvarðaður skjárinn. Ef þú ekki gerðir, gerðu svo vel að kvarða áður en þú leikur."
"APP_CALIBRATE_YOUR_MONITOR";;"Best player experience can be achieved with properly calibrated monitor. If you have not, please do it before you play.";"Meilleure expérience de joueur peut être réalisé avec écran correctement calibré. Si vous ne l'avez pas, s.v.p. le calibrez avant de jouer.";;;;;;;;;;;;;;;"このゲームは、適切に調整したモニターから最高のプレイができます。調整していなかったら、プレイする前に調整してください。";;;"본 게임은 적절히 보정된 모니터에서 최상으로 즐길 수 있습니다. 보정하지 않았다면 플레이하기 전에 보정해 주십시오.";;;;;;;"このゲームはてきせつにちょうせいした モニターからさいこうのプレイができます。ちょうせいして いなかったらプレイするまえにちょうせいしてください。";"Best leikmaður reynsla er getur náðist með rétt kvarðaður skjárinn. Ef þú ekki gerðir, gerðu svo vel að kvarða áður en þú leikur."
"COPYRIGHT_MSG";;"All rights reserved.";"Tous les droits sont réservés.";;;;;;;;;;;;;;;"全著作権所有。";;;"모든 권리 보유.";;;;;;;"ぜん ちょさくけん しょゆう。";"Allur réttur áskilinn."
"MENU_LABEL_NEW_WORLD";"";"New world";"Nouveau monde";"Nuevo mundo";"Neue Welt";"Nuovo mondo";"Novo mundo";"Novo mundo";"Новый мир";"Νέο κόσμο";"Yeni Dünya";"Ny verden";"Ny verden";"Ny värld";"Nieuwe wereld";"Nowy Świat";"Uusi maailma";"新しい世界";"新世界";"新世界";"새 세계";"Nový svět";"Új világ";"Lume noua";"โลกใหม่";"Нов свят";"עולם חדש";"あたらしいせかい";"Nýr heimur"
"MENU_LABEL_NEW_WORLD";"";"New world";"Nouveau monde";"Nuevo mundo";"Neue Welt";"Nuovo mondo";"Novo mundo";"Novo mundo";"Новый мир";"Νέο κόσμο";"Yeni Dünya";"Ny verden";"Ny verden";"Ny värld";"Nieuwe wereld";"Nowy Świat";"Uusi maailma";"新しい世界";"新世界";"新世界";"새 세계";"Nový svět";"Új világ";"Lume noua";"โลกใหม่";"Нов свят";"עולם חדש";"あたらしい せかい";"Nýr heimur"
1 STRING_ID IETF language tag(s) without dash enUS frFR esES deDE itIT ptBR ptPT ruRU elGR trTR daDK noNB svSE nlNL plPL fiFI jaJP zhCN zhTW koKR csCZ huHU roRO thTH bgBG heIL jakanaJP isIC
2 APP_CALIBRATE_YOUR_MONITOR Best player experience can be achieved with properly calibrated monitor. If you have not, please do it before you play. Meilleure expérience de joueur peut être réalisé avec écran correctement calibré. Si vous ne l'avez pas, s.v.p. le calibrez avant de jouer. このゲームは、適切に調整したモニターから最高のプレイができます。調整していなかったら、プレイする前に調整して下さい。 このゲームは、適切に調整したモニターから最高のプレイができます。調整していなかったら、プレイする前に調整してください。 본 게임은 적절히 보정된 모니터에서 최상으로 즐길 수 있습니다. 보정하지 않았다면 플레이하기 전에 보정해 주십시오. このゲームは てきせつに ちょうせいしたモニターから さいこうのプレイができます。ちょうせいして いなかったら プレイするまえに ちょうせいしてください。 このゲームは、てきせつにちょうせいした モニターからさいこうのプレイができます。ちょうせいして いなかったら、プレイするまえにちょうせいしてください。 Best leikmaður reynsla er getur náðist með rétt kvarðaður skjárinn. Ef þú ekki gerðir, gerðu svo vel að kvarða áður en þú leikur.
3 COPYRIGHT_MSG All rights reserved. Tous les droits sont réservés. 全著作権所有。 모든 권리 보유. ぜん ちょさくけん しょゆう。 Allur réttur áskilinn.
4 MENU_LABEL_NEW_WORLD New world Nouveau monde Nuevo mundo Neue Welt Nuovo mondo Novo mundo Novo mundo Новый мир Νέο κόσμο Yeni Dünya Ny verden Ny verden Ny värld Nieuwe wereld Nowy Świat Uusi maailma 新しい世界 新世界 新世界 새 세계 Nový svět Új világ Lume noua โลกใหม่ Нов свят עולם חדש あたらしいせかい あたらしい せかい Nýr heimur
5
6

View File

@@ -315,9 +315,13 @@ constructor() : Font {
val glyphW = getWidth("" + ch)
sheetKey[prevInstance].renderInUse(
Math.round(x + getWidthSubstr(s, i + 1) - glyphW) // Interchar: pull punct right next to hangul to the left
+ if (i > 0 && isHangul(s[i - 1])) -3 else 0, Math.round(y) + if (prevInstance == SHEET_CJK_PUNCT)
-1
else if (prevInstance == SHEET_FW_UNI) (H - H_HANGUL) / 2 else 0, sheetX, sheetY)
+ if (i > 0 && isHangul(s[i - 1])) -3 else 0, Math.round(y) +
if (prevInstance == SHEET_CJK_PUNCT)
-1
else if (prevInstance == SHEET_FW_UNI)
(H - H_HANGUL) / 2
else 0,
sheetX, sheetY)
}

View File

@@ -175,6 +175,8 @@ constructor() : BasicGameState() {
}
override fun render(gc: GameContainer, sbg: StateBasedGame, g: Graphics) {
setBlendModeNormal()
Terrarum.gameConfig["smoothlighting"] = KeyToggler.isOn(KEY_LIGHTMAP_SMOOTH)
if (!g.isAntiAlias) g.isAntiAlias = true
@@ -284,16 +286,6 @@ constructor() : BasicGameState() {
g.fill(skyBox, skyColourFill)
}
private fun setBlendModeMul() {
GL11.glEnable(GL11.GL_BLEND)
GL11.glBlendFunc(GL11.GL_DST_COLOR, GL11.GL_ONE_MINUS_SRC_ALPHA)
}
private fun setBlendModeNormal() {
GL11.glDisable(GL11.GL_BLEND)
Terrarum.appgc.graphics.setDrawMode(Graphics.MODE_NORMAL)
}
fun sendNotification(msg: Array<String>) {
(notifinator.UI as Notification).sendNotification(Terrarum.appgc, update_delta, msg)
notifinator.setAsOpening()

View File

@@ -167,6 +167,48 @@ constructor(//properties
worldTime.update(delta)
}
fun terrainIterator(): Iterator<Int> {
return object : Iterator<Int> {
private var iteratorCount = 0
override fun hasNext(): Boolean {
return iteratorCount < width * height
}
override fun next(): Int {
val y = iteratorCount / width
val x = iteratorCount % width
// advance counter
iteratorCount += 1
return getTileFromTerrain(x, y)!!
}
}
}
fun wallIterator(): Iterator<Int> {
return object : Iterator<Int> {
private var iteratorCount = 0
override fun hasNext(): Boolean {
return iteratorCount < width * height
}
override fun next(): Int {
val y = iteratorCount / width
val x = iteratorCount % width
// advance counter
iteratorCount += 1
return getTileFromWall(x, y)!!
}
}
}
companion object {
@Transient val WALL = 0

View File

@@ -6,6 +6,8 @@ import com.torvald.terrarum.Terrarum
import com.torvald.terrarum.tileproperties.TileNameCode
import com.torvald.terrarum.tileproperties.TilePropCodex
import com.jme3.math.FastMath
import com.torvald.terrarum.setBlendModeMul
import com.torvald.terrarum.setBlendModeNormal
import org.lwjgl.opengl.GL11
import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics
@@ -455,13 +457,4 @@ object MapCamera {
private fun isBlendMul(b: Int?): Boolean = TILES_BLEND_MUL.contains(b)
private fun setBlendModeMul() {
GL11.glEnable(GL11.GL_BLEND)
GL11.glBlendFunc(GL11.GL_DST_COLOR, GL11.GL_ONE_MINUS_SRC_ALPHA)
}
private fun setBlendModeNormal() {
GL11.glDisable(GL11.GL_BLEND)
Terrarum.appgc.graphics.setDrawMode(Graphics.MODE_NORMAL)
}
}

View File

@@ -14,25 +14,24 @@ object MapGenerator {
private lateinit var random: Random
//private static float[] noiseArray;
private var SEED: Long = 0
private var WIDTH: Int = 0
private var HEIGHT: Int = 0
var WIDTH: Int = 0
var HEIGHT: Int = 0
//private lateinit var heightMap: IntArray
private lateinit var terrainMap: Array<BitSet>
private var DIRT_LAYER_DEPTH: Int = 0
private var TERRAIN_AVERAGE_HEIGHT: Int = 0
var DIRT_LAYER_DEPTH: Int = 0
var TERRAIN_AVERAGE_HEIGHT: Int = 0
private var minimumFloatingIsleHeight: Int = 0
private val noiseGradientStart = 0.67f
private val noiseGradientEnd = 0.56f
private val noiseGrdCaveEnd = 0.54f
private val HILL_WIDTH = 256 // power of two!
//private val MAX_HILL_HEIGHT = 100
private val TERRAIN_UNDULATION = 250
private val CAVE_LARGEST_FEATURE = 200
private val SIMPLEXGEN_LARGEST_FEATURE = 200
private var OCEAN_WIDTH = 400
private var SHORE_WIDTH = 120
@@ -41,14 +40,9 @@ object MapGenerator {
private var GLACIER_MOUNTAIN_WIDTH = 900
private val GLACIER_MOUNTAIN_HEIGHT = 300
private val CAVEGEN_PERTURB_RATE = 0.37f
private val CAVEGEN_PERTURB2_RATE = 0.25f
private val CAVEGEN_THRE_START = 0.87f
private val CAVEGEN_THRE_START = 0.95f
private val CAVEGEN_THRE_END = 0.67f
private val CAVEGEN_LARGEST_FEATURE = 256
private val CAVEGEN_LARGEST_FEATURE_PERTURB = 128
private var worldOceanPosition: Int = -1
private val TYPE_OCEAN_LEFT = 0
@@ -58,7 +52,9 @@ object MapGenerator {
private val GRASSCUR_RIGHT = 1
private val GRASSCUR_DOWN = 2
private val GRASSCUR_LEFT = 3
private val TILE_MACRO_ALL = -1
fun attachMap(map: GameMap) {
this.map = map
WIDTH = map.width
@@ -97,87 +93,62 @@ object MapGenerator {
terrainMap = raise3()
terrainMapToObjectMap()
fillMapByNoiseMap()
/**
* Done: more perturbed overworld (harder to supra-navigate)
* Todo: veined ore distribution (metals) -- use veined simplex noise
* Todo: clustered gem distribution (Groups: [Ruby, Sapphire], Amethyst, Yellow topaz, emerald, diamond) -- use regular simplex noise
* Todo: clustered gem distribution (clusters: [Ruby, Sapphire], Amethyst, Yellow topaz, emerald, diamond) -- use regular simplex noise
* Todo: Lakes! Aquifers! Lava chambers!
* Todo: deserts (variants: SAND_DESERT, SAND_RED)
* Todo: volcano(es?)
* Done: variants of beach (SAND, SAND_BEACH, SAND_BLACK, SAND_GREEN)
*/
carveCave(
caveGen(1.4f, 1.7f), TileNameCode.AIR, "Carving out cave...")
val noiseArray = arrayOf(
TaggedJoise("Carving caves", noiseRidged(1.7f, 1.4f), 1f, TILE_MACRO_ALL, TILE_MACRO_ALL, TileNameCode.AIR, NoiseFilterSqrt, CAVEGEN_THRE_START, CAVEGEN_THRE_END),
TaggedJoise("Collapsing caves", noiseBlobs(0.5f, 0.5f), 0.3f, TileNameCode.AIR, TileNameCode.STONE, TileNameCode.STONE, NoiseFilterUniform)
fillByMapNoFilterUnderground(
generate2DSimplexNoiseWorldSize(1f, 1f), 0.9f, TileNameCode.AIR, TileNameCode.STONE, "Collapsing caves...")
// random stone patches on grounds
//TaggedJoise(noiseBlobs(0.25f, 0.25f), 1.02f, TileNameCode.DIRT, TileNameCode.STONE, NoiseFilterQuadratic, noiseGradientEnd, noiseGradientStart),
// random dirt spots in caves
//TaggedJoise(noiseBlobs(2.5f, 2.5f), 0.98f, TileNameCode.STONE, TileNameCode.DIRT, NoiseFilterQuadratic, noiseGradientEnd, noiseGradientStart),
// random gravels in caves
//TaggedJoise(noiseBlobs(2.5f, 2.5f), 0.98f, TileNameCode.STONE, TileNameCode.GRAVEL, NoiseFilterQuadratic, noiseGradientEnd, noiseGradientStart),
/*fillByMapInverseGradFilter(
generate2DSimplexNoiseWorldSize(2.5f, 2.5f)
, 1.02f
, TileNameCode.DIRT
, TileNameCode.STONE
, "Planting stones on dirt layers..."
);
fillByMapInverseGradFilter(
generate2DSimplexNoiseWorldSize(2.5f, 2.5f)
, 0.98f
, TileNameCode.STONE
, TileNameCode.DIRT
, "Planting dirts..."
);
fillByMapInverseGradFilter(
generate2DSimplexNoiseWorldSize(2.5f, 2.5f)
, 0.92f
, TileNameCode.STONE
, GRAVEL
, "Planting gravels..."
);*/
// copper veins
//TaggedJoise(noiseRidged(2.2f, 2.2f), 1.67f, TileNameCode.STONE, TileNameCode.ORE_COPPER),
// separate copper veins
//TaggedJoise(noiseBlobs(1.3f, 1.3f), 0.75f, TileNameCode.ORE_COPPER, TileNameCode.STONE),
/**
* Plant ores
*/
/*fillByMap(
generate2DSimplexNoiseWorldSize(5, 5)
, 0.78f
, TileNameCode.STONE
, DIAMOND
, "Planting diamonds..."
);
// iron veins
//TaggedJoise(noiseRidged(2.2f, 2.2f), 1.69f, TileNameCode.STONE, TileNameCode.ORE_IRON),
// separate iron veins
//TaggedJoise(noiseBlobs(1.3f, 1.3f), 0.75f, TileNameCode.ORE_IRON, TileNameCode.STONE),
byte[] berylsArray = {RUBY, EMERALD, SAPPHIRE, TOPAZ, AMETHYST};
fillByMap(
generate2DSimplexNoiseWorldSize(5, 5)
, 0.8f
, TileNameCode.STONE
, berylsArray
, "Planting beryls..."
);
// silver veins
//TaggedJoise(noiseRidged(2.2f, 2.2f), 1.70f, TileNameCode.STONE, TileNameCode.ORE_SILVER),
// separate silver veins
//TaggedJoise(noiseBlobs(1.3f, 1.3f), 0.75f, TileNameCode.ORE_SILVER, TileNameCode.STONE),
fillByMap(
generate2DSimplexNoiseWorldSize(5, 5)
, 0.80f
, TileNameCode.STONE
, GOLD
, "Planting golds..."
);
fillByMap(
generate2DSimplexNoiseWorldSize(5, 5)
, 0.866f
, TileNameCode.STONE
, IRON
, "Planting irons..."
);
fillByMap(
generate2DSimplexNoiseWorldSize(5, 5)
, 0.88f
, TileNameCode.STONE
, COPPER
, "Planting coppers..."
);*/
// gold veins
//TaggedJoise(noiseRidged(2.2f, 2.2f), 1.71f, TileNameCode.STONE, TileNameCode.ORE_GOLD),
// separate gold veins
//TaggedJoise(noiseBlobs(1.3f, 1.3f), 0.75f, TileNameCode.ORE_GOLD, TileNameCode.STONE),
// topaz
//TaggedJoise(noiseBlobs(1.55f, 1.55f), 1.5f, TileNameCode.STONE, TileNameCode.RAW_TOPAZ),
// ruby/sapphire
//TaggedJoise(noiseBlobs(1.55f, 1.55f), 1.5f, TileNameCode.STONE, intArrayOf(TileNameCode.RAW_RUBY, TileNameCode.RAW_SAPPHIRE)),
// emerald
//TaggedJoise(noiseBlobs(1.55f, 1.55f), 1.5f, TileNameCode.STONE, TileNameCode.RAW_EMERALD),
// diamond
//TaggedJoise(noiseBlobs(1.45f, 1.45f), 1.5f, TileNameCode.STONE, TileNameCode.RAW_DIAMOND),
// amethyst
//TaggedJoise(noiseBlobs(1.45f, 1.45f), 1.5f, TileNameCode.STONE, TileNameCode.RAW_AMETHYST)
)
processNoiseLayers(noiseArray)
/** TODO Cobaltite, Ilmenite, Aurichalcum (and possibly pitchblende?) */
@@ -202,128 +173,40 @@ object MapGenerator {
/* 1. Raise */
/**
* Ridged 2D simplex noise with some perturbing
* @param xStretch
* *
* @param yStretch
* *
* @return
*/
private fun caveGen(xStretch: Float, yStretch: Float): Array<FloatArray> {
val noiseMap = Array(HEIGHT) { FloatArray(WIDTH) }
private fun noiseRidged(xStretch: Float, yStretch: Float): Joise {
val ridged = ModuleFractal()
ridged.setType(ModuleFractal.FractalType.RIDGEMULTI)
ridged.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC)
ridged.setNumOctaves(4)
ridged.setFrequency(1.0)
ridged.seed = SEED xor random.nextLong()
val simplexNoise = SimplexNoise(CAVEGEN_LARGEST_FEATURE, CAVEGEN_PERTURB_RATE, SEED)
val simplexNoisePerturbMap = SimplexNoise(CAVEGEN_LARGEST_FEATURE_PERTURB, 0.5f, SEED xor random.nextLong())
val ridged_autocorrect = ModuleAutoCorrect()
ridged_autocorrect.setRange(0.0, 1.0)
ridged_autocorrect.setSource(ridged)
val xEnd = WIDTH * yStretch
val yEnd = HEIGHT * xStretch
val ridged_scale = ModuleScaleDomain()
ridged_scale.setScaleX(xStretch.toDouble())
ridged_scale.setScaleY(yStretch.toDouble())
ridged_scale.setSource(ridged_autocorrect)
var lowestNoiseVal = 10000f
var highestNoiseVal = -10000f
for (y in 0..HEIGHT - 1) {
for (x in 0..WIDTH - 1) {
val ny = (y * (xEnd / WIDTH)).toInt()
val nx = (x * (yEnd / HEIGHT)).toInt()
val noiseInit = simplexNoise.getNoise(nx, ny) // [-1 , 1]
val perturbInit = simplexNoisePerturbMap.getNoise(nx, ny) * 0.5f + 0.5f // [0 , 1]
/** Ridging part ! */
val noiseFin = 1f - Math.abs(noiseInit) // [0 , 1]
val perturb = 1 - perturbInit * CAVEGEN_PERTURB2_RATE // [1 , 1-0.25]
val noisePerturbed = noiseFin * perturb // [0 , 1]
if (noisePerturbed < lowestNoiseVal) lowestNoiseVal = noisePerturbed
if (noisePerturbed > highestNoiseVal) highestNoiseVal = noisePerturbed
noiseMap[y][x] = noisePerturbed
}
}
// Auto-scaling noise
for (y in 0..HEIGHT - 1) {
for (x in 0..WIDTH - 1) {
val noiseInit = noiseMap[y][x] - lowestNoiseVal
val noiseFin = noiseInit * (1f / (highestNoiseVal - lowestNoiseVal))
val noiseThresholded = (if (noiseFin > gradientSqrt(y, CAVEGEN_THRE_START,
CAVEGEN_THRE_END))
1
else
0).toFloat()
noiseMap[y][x] = noiseThresholded
}
}
return noiseMap
return Joise(ridged_scale)
}
private fun generate2DSimplexNoiseWorldSize(xStretch: Float, yStretch: Float): Array<FloatArray> {
return generate2DSimplexNoise(WIDTH, HEIGHT, xStretch, yStretch)
private fun noiseBlobs(xStretch: Float, yStretch: Float): Joise {
val gradval = ModuleBasisFunction()
gradval.seed = SEED
gradval.setType(ModuleBasisFunction.BasisType.GRADVAL)
gradval.setInterpolation(ModuleBasisFunction.InterpolationType.QUINTIC)
val gradval_scale = ModuleScaleDomain()
gradval_scale.setScaleX(1.0 / xStretch)
gradval_scale.setScaleY(1.0 / yStretch)
gradval_scale.setSource(gradval)
return Joise(gradval_scale)
}
/**
* Generate 2D array of simplex noise.
* @param sizeX
* *
* @param sizeY
* *
* @param xStretch
* *
* @param yStretch
* *
* @return matrix in ![x][y]!
*/
private fun generate2DSimplexNoise(sizeX: Int, sizeY: Int, xStretch: Float, yStretch: Float): Array<FloatArray> {
val simplexNoise = SimplexNoise(CAVE_LARGEST_FEATURE, 0.1f, SEED xor random.nextLong())
val xStart = 0f
val yStart = 0f
/** higher = denser.
* Recommended: (width or height) * 3
*/
val xEnd = WIDTH * yStretch
val yEnd = HEIGHT * xStretch
var lowestNoiseVal = 10000f
var highestNoiseVal = -10000f
val result = Array(sizeY) { FloatArray(sizeX) }
for (i in 0..sizeY - 1) {
for (j in 0..sizeX - 1) {
val x = (xStart + i * ((xEnd - xStart) / sizeX)).toInt()
val y = (yStart + j * ((yEnd - yStart) / sizeY)).toInt()
val noiseValue = (0.5 * (1 + simplexNoise.getNoise(x, y))).toFloat()
if (noiseValue < lowestNoiseVal) lowestNoiseVal = noiseValue
if (noiseValue > highestNoiseVal) highestNoiseVal = noiseValue
result[i][j] = noiseValue
}
}
// Auto-scaling noise
for (y in 0..HEIGHT - 1) {
for (x in 0..WIDTH - 1) {
val noiseInit = result[y][x] - lowestNoiseVal
val noiseFin = noiseInit * (1f / (highestNoiseVal - lowestNoiseVal))
result[y][x] = noiseFin
}
}
return result
}
private fun generateOcean(noiseArrayLocal: IntArray): IntArray {
val oceanLeftP1 = noiseArrayLocal[OCEAN_WIDTH]
@@ -333,13 +216,13 @@ object MapGenerator {
* Add ocean so that:
* +1| - -
* 0| - -- ...
* 0| - -- ...
* -1|______ -
* interpolated to
* +1| - -
* 0| _--- -- ...
* 0| _--- -- ...
* -1|__- -
* ↑-- Rough, white noise
@@ -388,8 +271,7 @@ object MapGenerator {
//println(lowland_shape_fractal.seed)
val lowland_autocorrect = ModuleAutoCorrect()
lowland_autocorrect.setLow(0.0)
lowland_autocorrect.setHigh(1.0)
lowland_autocorrect.setRange(0.0, 1.0)
lowland_autocorrect.setSource(lowland_shape_fractal)
val lowland_scale = ModuleScaleOffset()
@@ -418,8 +300,7 @@ object MapGenerator {
val highland_autocorrect = ModuleAutoCorrect()
highland_autocorrect.setSource(highland_shape_fractal)
highland_autocorrect.setLow(0.0)
highland_autocorrect.setHigh(1.0)
highland_autocorrect.setRange(0.0, 1.0)
val highland_scale = ModuleScaleOffset()
highland_scale.setSource(highland_autocorrect)
@@ -447,8 +328,7 @@ object MapGenerator {
val mountain_autocorrect = ModuleAutoCorrect()
mountain_autocorrect.setSource(mountain_shape_fractal)
mountain_autocorrect.setLow(0.0)
mountain_autocorrect.setHigh(1.0)
mountain_autocorrect.setRange(0.0, 1.0)
val mountain_scale = ModuleScaleOffset()
mountain_scale.setSource(mountain_autocorrect)
@@ -476,8 +356,7 @@ object MapGenerator {
val terrain_autocorrect = ModuleAutoCorrect()
terrain_autocorrect.setSource(terrain_type_fractal)
terrain_autocorrect.setLow(0.0)
terrain_autocorrect.setHigh(1.0)
terrain_autocorrect.setRange(0.0, 1.0)
val terrain_type_scale = ModuleScaleDomain()
terrain_type_scale.setScaleY(0.33)
@@ -508,7 +387,9 @@ object MapGenerator {
ground_select.setControlSource(highland_lowland_select)
val joise = Joise(ground_select)
// fill the area as Joise map
println("[mapgenerator] Raising and eroding terrain...")
for (y in 0..(TERRAIN_UNDULATION - 1)) {
for (x in 0..WIDTH) {
val map: Boolean = (
@@ -606,8 +487,8 @@ object MapGenerator {
}
}
private fun terrainMapToObjectMap() {
println("[mapgenerator] Shaping world as processed...")
private fun fillMapByNoiseMap() {
println("[mapgenerator] Shaping world...")
// generate dirt-stone transition line
// use catmull spline
val dirtStoneLine = IntArray(WIDTH)
@@ -620,12 +501,12 @@ object MapGenerator {
splineControlPoints[x] = Pair(x * POINTS_GAP, y)
if (terrainMap[y].get(splineControlPoints[x].first)) break
}
println("Spline[$x] x: ${splineControlPoints[x].first}, " +
"y: ${splineControlPoints[x].second}")
// println("Spline[$x] x: ${splineControlPoints[x].first}, " +
// "y: ${splineControlPoints[x].second}")
}
// do interpolation
for (x in 0..dirtStoneLine.size) {
for (x in 0..dirtStoneLine.size - 1) {
val x_1 = x / POINTS_GAP
val splineX0 = splineControlPoints[ clamp(x_1 - 1, 0, dirtStoneLine.size / POINTS_GAP) ].first
@@ -641,7 +522,7 @@ object MapGenerator {
if (x in POINTS_GAP - 1..WIDTH - 2 * POINTS_GAP) {
dirtStoneLine[x] = Math.round(FastMath.interpolateCatmullRom(
(x - splineX1) / POINTS_GAP.toFloat(),
0.01f,
-0.3f,//0.01f,
splineP0,
splineP1,
splineP2,
@@ -649,11 +530,14 @@ object MapGenerator {
))
}
else {
interpolateCosine(
dirtStoneLine[x] = Math.round(FastMath.interpolateCatmullRom(
(x - splineX1) / POINTS_GAP.toFloat(),
-0.3f,//0.01f,
splineP0,
splineP1,
splineP2
)
splineP2,
splineP3
))
}
}
@@ -675,283 +559,138 @@ object MapGenerator {
/* 2. Carve */
private fun carveCave(noisemap: Array<FloatArray>, tile: Int, message: String) {
println("[mapgenerator] " + message)
for (i in 0..HEIGHT - 1) {
for (j in 0..WIDTH - 1) {
if (noisemap[i][j] > 0.9) {
map.setTileTerrain(j, i, tile)
}
}
}
}
/**
* Carve (place air block) by noisemap, inversed gradation filter applied.
* Carve (place specified block) by noisemap, inversed gradation filter applied.
* @param map noisemap
* *
* @param scarcity higher = larger blob
* *
* @param scarcity higher == rarer
* * 1.0 is a default value. This value works as a multiplier to the gradient filter.
* @param tile
* *
* @param message
*/
private fun carveByMap(noisemap: Array<FloatArray>, scarcity: Float, tile: Int, message: String) {
private fun carveByMap(noisemap: Any, scarcity: Float, tile: Int, message: String,
filter: NoiseFilter = NoiseFilterQuadratic,
filterStart: Float = noiseGradientStart,
filterEnd: Float = noiseGradientEnd) {
println("[mapgenerator] " + message)
for (i in 0..HEIGHT - 1) {
for (j in 0..WIDTH - 1) {
if (noisemap[i][j] > gradientQuadratic(i, noiseGradientStart, noiseGrdCaveEnd) * scarcity) {
map.setTileTerrain(j, i, tile)
for (y in 0..HEIGHT - 1) {
for (x in 0..WIDTH - 1) {
val noise: Float = when (noisemap) {
is Joise ->
noisemap.get(
x.toDouble() / 48.0, // 48: Fixed value
y.toDouble() / 48.0
).toFloat()
is TaggedSimplexNoise -> noisemap.noiseModule.getNoise(
Math.round(x / noisemap.xStretch),
Math.round(y / noisemap.yStretch)
)
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.setTileTerrain(x, y, tile)
}
}
}
}
/**
* Fill by noisemap, gradation filter applied.
* @param map noisemap
* *
* @param scarcity higher = larger blob
* *
* @param replaceFrom
* *
* @param tile
* *
* @param message
*/
private fun fillByMap(noisemap: Array<FloatArray>, scarcity: Float, replaceFrom: Int, tile: Int, message: String) {
private fun fillByMap(noisemap: Any, scarcity: Float, replaceFrom: Int, replaceTo: Int, message: String,
filter: NoiseFilter = NoiseFilterQuadratic,
filterStart: Float = noiseGradientStart,
filterEnd: Float = noiseGradientEnd) {
println("[mapgenerator] " + message)
for (i in 0..HEIGHT - 1) {
for (j in 0..WIDTH - 1) {
if (noisemap[i][j] > getNoiseGradient(i, noiseGradientStart, noiseGradientEnd) * scarcity && map.getTileFromTerrain(j, i) == replaceFrom) {
map.setTileTerrain(j, i, tile)
for (y in 0..HEIGHT - 1) {
for (x in 0..WIDTH - 1) {
val noise: Float = when (noisemap) {
is Joise ->
noisemap.get(
x.toDouble() / 48.0, // 48: Fixed value
y.toDouble() / 48.0
).toFloat()
is TaggedSimplexNoise -> noisemap.noiseModule.getNoise(
Math.round(x / noisemap.xStretch),
Math.round(y / noisemap.yStretch)
)
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, replaceTo)
}
}
}
}
/**
* Fill by noisemap, inversed gradation filter applied.
* @param map noisemap
* *
* @param scarcity higher = larger blob
* *
* @param replaceFrom
* *
* @param tile
* *
* @param message
*/
private fun fillByMapInverseGradFilter(noisemap: Array<FloatArray>, scarcity: Float, replaceFrom: Int, tile: Int, message: String) {
private fun fillByMap(noisemap: Any, scarcity: Float, replaceFrom: Int, tile: IntArray, message: String,
filter: NoiseFilter = NoiseFilterQuadratic,
filterStart: Float = noiseGradientStart,
filterEnd: Float = noiseGradientEnd) {
println("[mapgenerator] " + message)
for (i in 0..HEIGHT - 1) {
for (j in 0..WIDTH - 1) {
if (noisemap[i][j] > getNoiseGradientInversed(i, noiseGradientEnd, noiseGradientStart) * scarcity
&& map.getTileFromTerrain(j, i) == replaceFrom) {
map.setTileTerrain(j, i, tile)
for (y in 0..HEIGHT - 1) {
for (x in 0..WIDTH - 1) {
val noise: Float = when (noisemap) {
is Joise ->
noisemap.get(
x.toDouble() / 48.0, // 48: Fixed value
y.toDouble() / 48.0
).toFloat()
is TaggedSimplexNoise -> noisemap.noiseModule.getNoise(
Math.round(x / noisemap.xStretch),
Math.round(y / noisemap.yStretch)
)
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)])
}
}
}
}
/**
* Fill by noisemap, no filter applied. Takes
*
* noiseGradientStart / scarcity
* as carving threshold.
* @param map noisemap
* *
* @param scarcity higher = larger blob
* *
* @param replaceFrom
* *
* @param tile
* *
* @param message
*/
private fun fillByMapNoFilter(noisemap: Array<FloatArray>, scarcity: Float, replaceFrom: Int, tile: Int, message: String) {
println("[mapgenerator] " + message)
private fun processNoiseLayers(noiseRecords: Array<TaggedJoise>) {
for (record in noiseRecords) {
println("[mapgenerator] ${record.message}...")
for (y in 0..HEIGHT - 1) {
for (x in 0..WIDTH - 1) {
val noise: Float = record.noiseModule.get(
x.toDouble() / 48.0, // 48: Fixed value
y.toDouble() / 48.0
).toFloat()
for (i in 0..HEIGHT - 1) {
for (j in 0..WIDTH - 1) {
if (noisemap[i][j] > noiseGradientStart * scarcity && map.getTileFromTerrain(j, i) == replaceFrom) {
map.setTileTerrain(j, i, tile)
val fromTerr = record.replaceFromTerrain
val fromWall = record.replaceFromWall
val to: Int = when(record.replaceTo) {
is Int -> record.replaceTo as Int
is IntArray -> (record.replaceTo as IntArray)[random.nextInt((record.replaceTo as IntArray).size)]
else -> throw IllegalArgumentException("[mapgenerator] Unknown replaceTo tile type '${record.replaceTo.javaClass.canonicalName}': Only 'kotlin.Int' and 'kotlin.IntArray' is valid.")
}
if (to == TILE_MACRO_ALL) throw IllegalArgumentException("[mapgenerator] Invalid replaceTo: TILE_MACRO_ALL")
val threshold = record.filter.getGrad(y, record.filterArg1, record.filterArg2)
if (noise > threshold * record.scarcity) {
if ((map.getTileFromTerrain(x, y) == fromTerr || fromTerr == TILE_MACRO_ALL)
&& (map.getTileFromWall(x, y) == fromWall || fromWall == TILE_MACRO_ALL)) {
map.setTileTerrain(x, y, to)
}
}
}
}
}
}
private fun fillByMapNoFilterUnderground(noisemap: Array<FloatArray>, scarcity: Float, replaceFrom: Int, replaceTo: Int, message: String) {
println("[mapgenerator] " + message)
for (i in 0..HEIGHT - 1) {
for (j in 0..WIDTH - 1) {
if (noisemap[i][j] > noiseGradientStart * scarcity
&& map.getTileFromTerrain(j, i) ?: 0 == replaceFrom
&& map.getTileFromWall(j, i) ?: 0 == replaceTo
) {
map.setTileTerrain(j, i, replaceTo)
}
}
}
}
private fun fillByMap(noisemap: Array<FloatArray>, scarcity: Float, replaceFrom: Int, tile: IntArray, message: String) {
println("[mapgenerator] " + message)
for (i in 0..HEIGHT - 1) {
for (j in 0..WIDTH - 1) {
if (noisemap[i][j] > getNoiseGradient(i, noiseGradientStart, noiseGradientEnd) * scarcity && map.getTileFromTerrain(j, i) == replaceFrom) {
map.setTileTerrain(j, i, tile[random.nextInt(tile.size)])
}
}
}
}
private fun getNoiseGradient(x: Int, start: Float, end: Float): Float {
return gradientQuadratic(x, start, end)
}
private fun getNoiseGradientInversed(x: Int, start: Float, end: Float): Float {
return gradientMinusQuadratic(x, start, end)
}
private fun gradientSqrt(func_argX: Int, start: Float, end: Float): Float {
val graph_gradient = (end - start) / FastMath.sqrt((HEIGHT - TERRAIN_AVERAGE_HEIGHT).toFloat()) * FastMath.sqrt((func_argX - TERRAIN_AVERAGE_HEIGHT).toFloat()) + start
if (func_argX < TERRAIN_AVERAGE_HEIGHT) {
return start
} else if (func_argX >= HEIGHT) {
return end
} else {
return graph_gradient
}
}
/**
* Quadratic polynomial
* (16/9) * (start-end)/height^2 * (x-height)^2 + end
* 16/9: terrain is formed from 1/4 of height.
* 1 - (1/4) = 3/4, reverse it and square it.
* That makes 16/9.
* Shape:
* cavity -
* small
* -
* -
* --
* ----
* cavity --------
* large ----------------
* @param func_argX
* *
* @param start
* *
* @param end
* *
* @return
*/
private fun gradientQuadratic(func_argX: Int, start: Float, end: Float): Float {
val graph_gradient = FastMath.pow(FastMath.sqr((1 - TERRAIN_AVERAGE_HEIGHT).toFloat()), -1f) * // 1/4 -> 3/4 -> 9/16 -> 16/9
(start - end) / FastMath.sqr(HEIGHT.toFloat()) *
FastMath.sqr((func_argX - HEIGHT).toFloat()) + end
if (func_argX < TERRAIN_AVERAGE_HEIGHT) {
return start
} else if (func_argX >= HEIGHT) {
return end
} else {
return graph_gradient
}
}
/**
* Double Quadratic polynomial
* (16/9) * (start-end)/height^2 * (x-height)^2 + end
* 16/9: terrain is formed from 1/4 of height.
* 1 - (1/4) = 3/4, reverse it and square it.
* That makes 16/9.
* Shape:
* cavity -
* small
* -
* -
* --
* ----
* cavity --------
* large ----------------
* @param func_argX
* *
* @param start
* *
* @param end
* *
* @return
*/
private fun gradientCubic(func_argX: Int, start: Float, end: Float): Float {
val graph_gradient = -FastMath.pow(FastMath.pow((1 - TERRAIN_AVERAGE_HEIGHT).toFloat(), 3f), -1f) * // 1/4 -> 3/4 -> 9/16 -> 16/9
(start - end) / FastMath.pow(HEIGHT.toFloat(), 3f) *
FastMath.pow((func_argX - HEIGHT).toFloat(), 3f) + end
if (func_argX < TERRAIN_AVERAGE_HEIGHT) {
return start
} else if (func_argX >= HEIGHT) {
return end
} else {
return graph_gradient
}
}
/**
* Quadratic polynomial
* -(16/9) * (start-end)/height^2 * (x - 0.25 * height)^2 + start
* 16/9: terrain is formed from 1/4 of height.
* 1 - (1/4) = 3/4, reverse it and square it.
* That makes 16/9.
* Shape:
* cavity _
* small
* _
* _
* __
* ____
* cavity ________
* large ________________
* @param func_argX
* *
* @param start
* *
* @param end
* *
* @return
*/
private fun gradientMinusQuadratic(func_argX: Int, start: Float, end: Float): Float {
val graph_gradient = -FastMath.pow(FastMath.sqr((1 - TERRAIN_AVERAGE_HEIGHT).toFloat()), -1f) * // 1/4 -> 3/4 -> 9/16 -> 16/9
(start - end) / FastMath.sqr(HEIGHT.toFloat()) *
FastMath.sqr((func_argX - TERRAIN_AVERAGE_HEIGHT).toFloat()) + start
if (func_argX < TERRAIN_AVERAGE_HEIGHT) {
return start
} else if (func_argX >= HEIGHT) {
return end
} else {
return graph_gradient
}
}
private fun generateFloatingIslands() {
println("[mapgenerator] Placing floating islands...")
@@ -1197,4 +936,13 @@ object MapGenerator {
private fun clamp(x: Int, min: Int, max: Int): Int = if (x < min) min else if (x > max) max else x
data class TaggedSimplexNoise(var noiseModule: SimplexNoise, var xStretch: Float, var yStretch: Float)
data class TaggedJoise(var message: String,
var noiseModule: Joise, var scarcity: Float,
var replaceFromTerrain: Int, var replaceFromWall: Int,
var replaceTo: Any,
var filter: NoiseFilter = NoiseFilterQuadratic,
var filterArg1: Float = noiseGradientStart,
var filterArg2: Float = noiseGradientEnd)
}

View File

@@ -5,6 +5,7 @@ import com.torvald.JsonFetcher
import com.torvald.JsonWriter
import com.torvald.terrarum.langpack.Lang
import org.lwjgl.input.Controllers
import org.lwjgl.opengl.GL11
import org.newdawn.slick.AppGameContainer
import org.newdawn.slick.Font
import org.newdawn.slick.GameContainer
@@ -329,4 +330,14 @@ constructor(gamename: String) : StateBasedGame(gamename) {
}
}
fun main(args: Array<String>) = Terrarum.main(args)
fun main(args: Array<String>) = Terrarum.main(args)
fun setBlendModeMul() {
GL11.glEnable(GL11.GL_BLEND)
GL11.glBlendFunc(GL11.GL_DST_COLOR, GL11.GL_ONE_MINUS_SRC_ALPHA)
}
fun setBlendModeNormal() {
GL11.glEnable(GL11.GL_BLEND)
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA)
}

View File

@@ -90,12 +90,6 @@ Magical/Surreal: Use 24 Bits
* Base mass: 60 kg
## Custom pattern making ##
- Players can create their own décors (hang on wall), dresses.
- Two looms (216 colour mode, 4096 colour mode)
## Food/Potion dose ##
Scale ^ 3 ^ (3/4) == (ThisWgt / TargetWgt) ^ (3/4)

View File

@@ -0,0 +1,19 @@
## Gadgets ##
### Looms for custom pattern ###
- Players can create their own décors (hang on wall), dresses.
- Two looms (216 colour mode, 4096 colour mode)
### Music making ###
- Automated glockenspiel thingy
- Single tile can hold 48 notes, single track
- Work like Modtracker, incl. physical arrangements
Arrangements in the map
Time →→→→
voice 1 → # # # # # # #
voice 2 → # # # # # # #
↑ played simultaneously along the X-axis

View File

@@ -1,7 +1,7 @@
## Format ##
* Save meta
- Binary (for more security)
- GZip'd binary (for more security)
- Filename : world (with no extension)
|Type |Mnemonic |Description |
@@ -11,10 +11,10 @@
|Byte |NULL |String terminator |
|Byte[8] |terraseed |Terrain seed |
|Byte[8] |rogueseed |Randomiser seed |
|Byte[32] |hash1 |SHA-256 hash of worldinfo1 being stored|
|Byte[32] |hash2 |SHA-256 hash of worldinfo2 being stored|
|Byte[32] |hash3 |SHA-256 hash of worldinfo3 being stored|
|Byte[32] |hash4 |SHA-256 hash of worldinfo4 being stored|
|Byte[32] |hash1 |SHA-256 hash of worldinfo1 being stored (when not zipped)|
|Byte[32] |hash2 |SHA-256 hash of worldinfo2 being stored (when not zipped)|
|Byte[32] |hash3 |SHA-256 hash of worldinfo3 being stored (when not zipped)|
|Byte[32] |hash4 |SHA-256 hash of worldinfo4 being stored (when not zipped)|
Endianness: Big
@@ -25,10 +25,10 @@
* Prop data
- GZip'd CSV
- Filename : worldinfo2 -- tileprop.csv
worldinfo3 -- itemprop.csv
worldinfo4 -- materialprop.csv
(with no extension)
- Filename : (with no extension)
worldinfo2 -- tileprop
worldinfo3 -- itemprop
worldinfo4 -- materialprop
* Human-readable
@@ -39,8 +39,7 @@
## How it works ##
* If hash discrepancy has detected, (hash of csv in save dir != stored hash || hash of TEMD != stored hash)
printout "Save file corrupted. Continue?" with prompt "Yes/No"
* If hash discrepancy has detected, (hash of csv in save dir != stored hash || hash of TEMD != stored hash), printout "Save file corrupted. Continue?" with prompt "Yes/No"
Directory:
@@ -48,10 +47,10 @@ Directory:
--- 2a93bc5fd...f823 Actor/Faction/etc. data
--- 423bdc838...93bd Actor/Faction/etc. data
--- Items_list.txt Human-readable
--- Materials_list.txt Human-redable
--- Materials_list.txt Human-readable
--- Tiles_list.txt Human-readable
--- world save meta (binary)
--- worldinfo1 TEMD (binary)
--- worldinfo2 tileprop
--- worldinfo3 itemprop
--- worldinfo4 materialprop
--- world save meta (binary, GZip)
--- worldinfo1 TEMD (binary, GZip)
--- worldinfo2 tileprop (GZip)
--- worldinfo3 itemprop (GZip)
--- worldinfo4 materialprop (GZip)

View File

@@ -3,6 +3,7 @@ package com.torvald.terrarum.console
import com.torvald.colourutil.Col4096
import com.torvald.RasterWriter
import com.torvald.terrarum.Terrarum
import com.torvald.terrarum.tileproperties.TileNameCode
import java.io.*
import java.util.HashMap
@@ -15,7 +16,7 @@ class ExportMap : ConsoleCommand {
//private var mapData: ByteArray? = null
// private var mapDataPointer = 0
private val colorTable = HashMap<Byte, Col4096>()
private val colorTable = HashMap<Int, Col4096>()
override fun execute(args: Array<String>) {
if (args.size == 2) {
@@ -24,8 +25,8 @@ class ExportMap : ConsoleCommand {
var mapData = ByteArray(Terrarum.game.map.width * Terrarum.game.map.height * 3)
var mapDataPointer = 0
for (tile in Terrarum.game.map.layerTerrain) {
val colArray = (colorTable as Map<Byte, Col4096>)
for (tile in Terrarum.game.map.terrainIterator()) {
val colArray = (colorTable as Map<Int, Col4096>)
.getOrElse(tile, { Col4096(0xFFF) }).toByteArray()
for (i in 0..2) {
@@ -71,222 +72,45 @@ class ExportMap : ConsoleCommand {
}
private fun buildColorTable() {
colorTable.put(AIR, Col4096(0xCEF))
colorTable.put(STONE, Col4096(0x887))
colorTable.put(DIRT, Col4096(0x763))
colorTable.put(GRASS, Col4096(0x251))
colorTable.put(TileNameCode.AIR, Col4096(0xCEF))
colorTable.put(TileNameCode.STONE, Col4096(0x888))
colorTable.put(TileNameCode.DIRT, Col4096(0x753))
colorTable.put(TileNameCode.GRASS, Col4096(0x472))
colorTable.put(COPPER, Col4096(0x6A8))
colorTable.put(IRON, Col4096(0xC75))
colorTable.put(GOLD, Col4096(0xCB6))
colorTable.put(ILMENITE, Col4096(0x8AB))
colorTable.put(AURICHALCUM, Col4096(0xD92))
colorTable.put(SILVER, Col4096(0xDDD))
colorTable.put(TileNameCode.ORE_COPPER, Col4096(0x6A8))
colorTable.put(TileNameCode.ORE_IRON, Col4096(0xC75))
colorTable.put(TileNameCode.ORE_GOLD, Col4096(0xA87))
colorTable.put(TileNameCode.ORE_ILMENITE, Col4096(0x8AB))
colorTable.put(TileNameCode.ORE_AURICHALCUM, Col4096(0xD92))
colorTable.put(TileNameCode.ORE_SILVER, Col4096(0xDDD))
colorTable.put(DIAMOND, Col4096(0x9CE))
colorTable.put(RUBY, Col4096(0xB10))
colorTable.put(EMERALD, Col4096(0x0B1))
colorTable.put(SAPPHIRE, Col4096(0x01B))
colorTable.put(TOPAZ, Col4096(0xC70))
colorTable.put(AMETHYST, Col4096(0x70C))
colorTable.put(TileNameCode.RAW_DIAMOND, Col4096(0x2BF))
colorTable.put(TileNameCode.RAW_RUBY, Col4096(0xB10))
colorTable.put(TileNameCode.RAW_EMERALD, Col4096(0x0B1))
colorTable.put(TileNameCode.RAW_SAPPHIRE, Col4096(0x01B))
colorTable.put(TileNameCode.RAW_TOPAZ, Col4096(0xC70))
colorTable.put(TileNameCode.RAW_AMETHYST, Col4096(0x70C))
colorTable.put(WATER, Col4096(0x038))
colorTable.put(LAVA, Col4096(0xF50))
colorTable.put(TileNameCode.WATER, Col4096(0x038))
colorTable.put(TileNameCode.LAVA, Col4096(0xF50))
colorTable.put(SAND, Col4096(0xDCA))
colorTable.put(GRAVEL, Col4096(0x664))
colorTable.put(TileNameCode.SAND, Col4096(0xDDB))
colorTable.put(TileNameCode.SAND_WHITE, Col4096(0xFFD))
colorTable.put(TileNameCode.SAND_RED, Col4096(0xA32))
colorTable.put(TileNameCode.SAND_DESERT, Col4096(0xEDB))
colorTable.put(TileNameCode.SAND_BLACK, Col4096(0x444))
colorTable.put(TileNameCode.SAND_GREEN, Col4096(0x9A6))
colorTable.put(ICE_NATURAL, Col4096(0x9AB))
colorTable.put(ICE_MAGICAL, Col4096(0x7AC))
colorTable.put(ICE_FRAGILE, Col4096(0x6AF))
colorTable.put(SNOW, Col4096(0xCDE))
colorTable.put(TileNameCode.GRAVEL, Col4096(0x664))
colorTable.put(TileNameCode.GRAVEL_GREY, Col4096(0x999))
colorTable.put(TileNameCode.ICE_NATURAL, Col4096(0x9AB))
colorTable.put(TileNameCode.ICE_MAGICAL, Col4096(0x7AC))
colorTable.put(TileNameCode.ICE_FRAGILE, Col4096(0x6AF))
colorTable.put(TileNameCode.SNOW, Col4096(0xCDE))
}
companion object {
private val AIR: Byte = 0
private val STONE: Byte = 1
private val DIRT: Byte = 2
private val GRASS: Byte = 3
private val SAND: Byte = 13
private val GRAVEL: Byte = 14
private val COPPER: Byte = 15
private val IRON: Byte = 16
private val GOLD: Byte = 17
private val SILVER: Byte = 18
private val ILMENITE: Byte = 19
private val AURICHALCUM: Byte = 20
private val DIAMOND: Byte = 25
private val RUBY: Byte = 21
private val EMERALD: Byte = 22
private val SAPPHIRE: Byte = 23
private val TOPAZ: Byte = 24
private val AMETHYST: Byte = 26
private val SNOW: Byte = 27
private val ICE_FRAGILE: Byte = 28
private val ICE_NATURAL: Byte = 29
private val ICE_MAGICAL: Byte = 30
private val WATER = 239.toByte()
private val LAVA = 255.toByte()
}
}
/*
package com.torvald.terrarum.console;
import com.torvald.colourutil.Col4096;
import com.torvald.RasterWriter;
import com.torvald.terrarum.terrarum;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.*;
import java.io.*;
import java.util.Hashtable;
/**
* Created by minjaesong on 16-01-17.
*/
public class ExportMap implements console {
private byte[] mapData;
private int mapDataPointer = 0;
private static final byte AIR = 0;
private static final byte STONE = 1;
private static final byte DIRT = 2;
private static final byte GRASS = 3;
private static final byte SAND = 13;
private static final byte GRAVEL = 14;
private static final byte COPPER = 15;
private static final byte IRON = 16;
private static final byte GOLD = 17;
private static final byte SILVER = 18;
private static final byte ILMENITE = 19;
private static final byte AURICHALCUM = 20;
private static final byte DIAMOND = 25;
private static final byte RUBY = 21;
private static final byte EMERALD = 22;
private static final byte SAPPHIRE = 23;
private static final byte TOPAZ = 24;
private static final byte AMETHYST = 26;
private static final byte SNOW = 27;
private static final byte ICE_FRAGILE = 28;
private static final byte ICE_NATURAL = 29;
private static final byte ICE_MAGICAL = 30;
private static final byte WATER = (byte) 239;
private static final byte LAVA = (byte) 255;
private Hashtable<Byte, Col4096> colorTable = new Hashtable<>();
@Override
public void execute(String[] args) {
if (args.length == 2) {
buildColorTable();
mapData = new byte[terrarum.game.map.getWidth() * terrarum.game.map.getHeight() * 3];
for (byte tile : terrarum.game.map.getLayerTerrain()) {
byte[] colArray = colorTable.getOrDefault(tile, new Col4096(0xFFF))
.toByteArray();
for (int i = 0; i < 3; i++) {
mapData[mapDataPointer + i] = colArray[i];
}
mapDataPointer += 3;
}
String dir = terrarum.defaultDir + "/Exports/";
File dirAsFile = new File(dir);
if (!dirAsFile.exists()) {
dirAsFile.mkdir();
}
try {
RasterWriter.INSTANCE.writePNG_RGB(
terrarum.game.map.getWidth()
, terrarum.game.map.getHeight()
, mapData
, dir + args[1] + ".png"
);
new Echo().execute("ExportMap: exported to " + args[1] + ".png");
} catch (IOException e) {
new Echo().execute("ExportMap: IOException raised.");
e.printStackTrace();
}
mapData = null;
mapDataPointer = 0;
// Free up some memory
System.gc();
}
else{
printUsage();
}
}
@Override
public void printUsage() {
Echo echo = new Echo();
echo.execute("Usage: export <name>");
echo.execute("Exports current map into visible image.");
echo.execute("The image can be found at %adddata%/terrarum/Exports");
}
private void buildColorTable() {
colorTable.put(AIR, new Col4096(0xCEF));
colorTable.put(STONE, new Col4096(0x887));
colorTable.put(DIRT, new Col4096(0x763));
colorTable.put(GRASS, new Col4096(0x251));
colorTable.put(COPPER, new Col4096(0x6A8));
colorTable.put(IRON, new Col4096(0xC75));
colorTable.put(GOLD, new Col4096(0xCB6));
colorTable.put(ILMENITE, new Col4096(0x8AB));
colorTable.put(AURICHALCUM, new Col4096(0xD92));
colorTable.put(SILVER, new Col4096(0xDDD));
colorTable.put(DIAMOND, new Col4096(0x9CE));
colorTable.put(RUBY, new Col4096(0xB10));
colorTable.put(EMERALD, new Col4096(0x0B1));
colorTable.put(SAPPHIRE, new Col4096(0x01B));
colorTable.put(TOPAZ, new Col4096(0xC70));
colorTable.put(AMETHYST, new Col4096(0x70C));
colorTable.put(WATER, new Col4096(0x038));
colorTable.put(LAVA, new Col4096(0xF50));
colorTable.put(SAND, new Col4096(0xDCA));
colorTable.put(GRAVEL, new Col4096(0x664));
colorTable.put(ICE_NATURAL, new Col4096(0x9AB));
colorTable.put(ICE_MAGICAL, new Col4096(0x7AC));
colorTable.put(ICE_FRAGILE, new Col4096(0x6AF));
colorTable.put(SNOW, new Col4096(0xCDE));
}
}
*/

View File

@@ -10,16 +10,10 @@ class Help : ConsoleCommand {
override fun execute(args: Array<String>) {
val echo = Echo()
if (args.size == 1) {
for (i in 1..6) echo.execute(Lang["HELP_OTF_TEXT_$i"])
for (i in 1..6) echo.execute(Lang["HELP_OTF_MAIN_$i"])
}
else if (args[1].toLowerCase() == "slow") {
if (Terrarum.game.screenZoom < 1)
echo.execute(Lang["HELP_OTF_SLOW_IF_ZOOM"])
if (Terrarum.game.debugWindow.isVisible)
echo.execute(Lang["HELP_OTF_SLOW_IF_F3"])
for (i in 1..1) echo.execute(Lang["HELP_OTF_SLOW_$i"])
for (i in 1..4) echo.execute(Lang["HELP_OTF_SLOW_$i"])
}
else {
for (i in 1..6) echo.execute(Lang["HELP_OTF_MAIN_$i"])

View File

@@ -0,0 +1,8 @@
package com.torvald.terrarum.mapgenerator
/**
* Created by minjaesong on 16-03-31.
*/
interface NoiseFilter {
fun getGrad(func_argX: Int, start: Float, end: Float): Float
}

View File

@@ -0,0 +1,46 @@
package com.torvald.terrarum.mapgenerator
import com.jme3.math.FastMath
/**
* Double Quadratic polynomial
* (16/9) * (start-end)/height^2 * (x-height)^2 + end
* 16/9: terrain is formed from 1/4 of height.
* 1 - (1/4) = 3/4, reverse it and square it.
* That makes 16/9.
* Shape:
* cavity -
* small
* -
* -
* --
* ----
* cavity --------
* large ----------------
* @param func_argX
* *
* @param start
* *
* @param end
* *
* @return
* Created by minjaesong on 16-03-31.
*/
object NoiseFilterCubic : NoiseFilter {
override fun getGrad(func_argX: Int, start: Float, end: Float): Float {
val graph_gradient = -FastMath.pow(FastMath.pow((1 - MapGenerator.TERRAIN_AVERAGE_HEIGHT).toFloat(), 3f), -1f) * // 1/4 -> 3/4 -> 9/16 -> 16/9
(start - end) / FastMath.pow(MapGenerator.HEIGHT.toFloat(), 3f) *
FastMath.pow((func_argX - MapGenerator.HEIGHT).toFloat(), 3f) + end
if (func_argX < MapGenerator.TERRAIN_AVERAGE_HEIGHT) {
return start
} else if (func_argX >= MapGenerator.HEIGHT) {
return end
} else {
return graph_gradient
}
}
}

View File

@@ -0,0 +1,46 @@
package com.torvald.terrarum.mapgenerator
import com.jme3.math.FastMath
/**
* Quadratic polynomial
* -(16/9) * (start-end)/height^2 * (x - 0.25 * height)^2 + start
* 16/9: terrain is formed from 1/4 of height.
* 1 - (1/4) = 3/4, reverse it and square it.
* That makes 16/9.
* Shape:
* cavity _
* small
* _
* _
* __
* ____
* cavity ________
* large ________________
* @param func_argX
* *
* @param start
* *
* @param end
* *
* @return
* Created by minjaesong on 16-03-31.
*/
object NoiseFilterMinusQuadratic : NoiseFilter {
override fun getGrad(func_argX: Int, start: Float, end: Float): Float {
val graph_gradient = -FastMath.pow(FastMath.sqr((1 - MapGenerator.TERRAIN_AVERAGE_HEIGHT).toFloat()), -1f) * // 1/4 -> 3/4 -> 9/16 -> 16/9
(start - end) / FastMath.sqr(MapGenerator.HEIGHT.toFloat()) *
FastMath.sqr((func_argX - MapGenerator.TERRAIN_AVERAGE_HEIGHT).toFloat()) + start
if (func_argX < MapGenerator.TERRAIN_AVERAGE_HEIGHT) {
return start
} else if (func_argX >= MapGenerator.HEIGHT) {
return end
} else {
return graph_gradient
}
}
}

View File

@@ -0,0 +1,47 @@
package com.torvald.terrarum.mapgenerator
import com.jme3.math.FastMath
/**
* Quadratic polynomial
* (16/9) * (start-end)/height^2 * (x-height)^2 + end
* 16/9: terrain is formed from 1/4 of height.
* 1 - (1/4) = 3/4, reverse it and square it.
* That makes 16/9.
* Shape:
* cavity -
* small
* -
* -
* --
* ----
* cavity --------
* large ----------------
* @param func_argX
* *
* @param start
* *
* @param end
* *
* @return
*
* Created by minjaesong on 16-03-31.
*/
object NoiseFilterQuadratic : NoiseFilter {
override fun getGrad(func_argX: Int, start: Float, end: Float): Float {
val graph_gradient = FastMath.pow(FastMath.sqr((1 - MapGenerator.TERRAIN_AVERAGE_HEIGHT).toFloat()), -1f) * // 1/4 -> 3/4 -> 9/16 -> 16/9
(start - end) / FastMath.sqr(MapGenerator.HEIGHT.toFloat()) *
FastMath.sqr((func_argX - MapGenerator.HEIGHT).toFloat()) + end
if (func_argX < MapGenerator.TERRAIN_AVERAGE_HEIGHT) {
return start
} else if (func_argX >= MapGenerator.HEIGHT) {
return end
} else {
return graph_gradient
}
}
}

View File

@@ -0,0 +1,20 @@
package com.torvald.terrarum.mapgenerator
import com.jme3.math.FastMath
/**
* Created by minjaesong on 16-03-31.
*/
object NoiseFilterSqrt : NoiseFilter {
override fun getGrad(func_argX: Int, start: Float, end: Float): Float {
val graph_gradient = (end - start) / FastMath.sqrt((MapGenerator.HEIGHT - MapGenerator.TERRAIN_AVERAGE_HEIGHT).toFloat()) * FastMath.sqrt((func_argX - MapGenerator.TERRAIN_AVERAGE_HEIGHT).toFloat()) + start
if (func_argX < MapGenerator.TERRAIN_AVERAGE_HEIGHT) {
return start
} else if (func_argX >= MapGenerator.HEIGHT) {
return end
} else {
return graph_gradient
}
}
}

View File

@@ -0,0 +1,10 @@
package com.torvald.terrarum.mapgenerator
/**
* Created by minjaesong on 16-03-31.
*/
object NoiseFilterUniform : NoiseFilter {
override fun getGrad(func_argX: Int, start: Float, end: Float): Float {
return 1f
}
}

View File

@@ -60,7 +60,7 @@ class ConsoleWindow : UICanvas, UITypable {
// text and cursor
g.color = Color.white
g.drawString(input, 1f + drawOffX, drawOffY)
g.fillRect(inputDrawWidth.toFloat() + drawOffX, drawOffY, 2f, inputDrawHeight.toFloat())
g.fillRect(inputDrawWidth.toFloat() + drawOffX + 1, drawOffY, 2f, inputDrawHeight.toFloat())
// messages
for (i in 0..MESSAGES_DISPLAY_COUNT - 1) {

View File

@@ -116,6 +116,6 @@ constructor(override var width: Int, isBlackVariant: Boolean) : UICanvas {
companion object {
// private int messagesShowingIndex = 0;
val MESSAGES_DISPLAY = 2
val OPEN_CLOSE_TIME = 200
val OPEN_CLOSE_TIME = 160
}
}