From 6399c2d66bcc63079ca1e5ed3a34c3210d4b8f9c Mon Sep 17 00:00:00 2001 From: Song Minjae Date: Sun, 23 Apr 2017 22:53:49 +0900 Subject: [PATCH] Resolving issue #18 and #19 --- Known problems.md | 28 - assets/locales/nameset_dwarven.csv | 132 + assets/locales/nameset_exotic_deities.csv | 6 + assets/locales/nameset_scandinavian_f.csv | 7 +- assets/locales/tiles.csv | 5 + assets/modules/LoadOrder.csv | 2 +- assets/modules/basegame/materialprop.csv | 25 +- src/net/torvald/colourutil/ColourTemp.kt | 6 +- .../{terrarum => dataclass}/CircularArray.kt | 2 +- src/net/torvald/terrarum/DefaultConfig.kt | 4 + .../terrarum/StateGraphicComputerTest.kt | 4 +- src/net/torvald/terrarum/StateInGame.kt | 121 +- src/net/torvald/terrarum/StateStutterTest.kt | 65 + src/net/torvald/terrarum/StateUITest.kt | 4 +- src/net/torvald/terrarum/Terrarum.kt | 5 +- .../terrarum/gameactors/ActorHumanoid.kt | 2 +- .../terrarum/gameactors/ActorInventory.kt | 18 +- .../terrarum/gameactors/ActorWithPhysics.kt | 23 +- .../terrarum/gameactors/DroppedItem.kt | 2 +- .../terrarum/gameactors/ParticleBase.kt | 2 +- .../terrarum/gameactors/ParticleTestRain.kt | 2 +- .../terrarum/gameactors/PhysTestBall.kt | 2 +- .../torvald/terrarum/gameactors/Pocketed.kt | 13 +- .../terrarum/gamecontroller/GameController.kt | 123 +- .../torvald/terrarum/gameworld/GameWorld.kt | 4 +- .../terrarum/itemproperties/Calculate.kt | 7 +- .../terrarum/itemproperties/InventoryItem.kt | 30 +- .../terrarum/itemproperties/ItemCodex.kt | 18 +- .../peripheral/PeripheralVideoCard.kt | 2 +- .../torvald/terrarum/weather/WeatherMixer.kt | 2 +- .../GameDesign/BACKEND_DESIGN.md | 0 work_files/GameDesign/ECONOMY.md | 14 + .../GameDesign/ENVIRON.md | 0 .../GameDesign/MISC_FEATURES.md | 0 .../GameDesign/MISC_MECHNANICS.md | 15 +- work_files/Pickaxe Power.xlsx | Bin 40885 -> 41294 bytes .../dwarvenNameSelector.py | 21 + .../dwarven_name_selector/language_DWARF.txt | 2195 +++++++++++++++++ 38 files changed, 2670 insertions(+), 241 deletions(-) delete mode 100644 Known problems.md create mode 100644 assets/locales/nameset_dwarven.csv create mode 100644 assets/locales/nameset_exotic_deities.csv rename src/net/torvald/{terrarum => dataclass}/CircularArray.kt (98%) create mode 100644 src/net/torvald/terrarum/StateStutterTest.kt rename GAME_SYSTEM.md => work_files/GameDesign/BACKEND_DESIGN.md (100%) create mode 100644 work_files/GameDesign/ECONOMY.md rename ENVIRON.md => work_files/GameDesign/ENVIRON.md (100%) rename MISC_FEATURES.md => work_files/GameDesign/MISC_FEATURES.md (100%) rename MECHNANICS.md => work_files/GameDesign/MISC_MECHNANICS.md (89%) create mode 100644 work_files/dwarven_name_selector/dwarvenNameSelector.py create mode 100644 work_files/dwarven_name_selector/language_DWARF.txt diff --git a/Known problems.md b/Known problems.md deleted file mode 100644 index 82a285536..000000000 --- a/Known problems.md +++ /dev/null @@ -1,28 +0,0 @@ -# Unresolved # - -### Character ### - -* Arm behind the body seems unnatural - - -### Physics ### - - -### System ### - - - -# Resolved # - -* Cannot fit into single-tile width pit - Cause: Player/NPC looks slim enough to fit, but don't fit in the game - Solution: Player/NPC hitbox now have a width of 15 pixels. - -* Actor stick to wall and not get off - Cause: Unknown - Solution: Changed collision detection method to CCD (continuous collision detection) - -* Actor with mass <2 behaves erratically - Details: Velocity becomes NaN when jumped - Cause: Floating-point precision error? - Solution: Changed every physics variable that uses Float to Double \ No newline at end of file diff --git a/assets/locales/nameset_dwarven.csv b/assets/locales/nameset_dwarven.csv new file mode 100644 index 000000000..99e108812 --- /dev/null +++ b/assets/locales/nameset_dwarven.csv @@ -0,0 +1,132 @@ +# Nameset - Dwarven (DF) +# Picked randomly from its massive 2195 entries + +"HEADER";"LatinAlph";"HangulKoKR";"KanaJaJP";"CyrilRuRU";"AlphElGR";"HanziZhCN";"HanziZhTW";"AksonThTH";"AlefbetHeIL" +"NAMESET_DWARVEN_001";"Asdos"; +"NAMESET_DWARVEN_002";"Ngárak"; +"NAMESET_DWARVEN_003";"Dùstik"; +"NAMESET_DWARVEN_004";"Ish"; +"NAMESET_DWARVEN_005";"Reked"; +"NAMESET_DWARVEN_006";"Noval"; +"NAMESET_DWARVEN_007";"Feb"; +"NAMESET_DWARVEN_008";"Ostar"; +"NAMESET_DWARVEN_009";"Nicat"; +"NAMESET_DWARVEN_010";"Kogan"; +"NAMESET_DWARVEN_011";"Alud"; +"NAMESET_DWARVEN_012";"Bidok"; +"NAMESET_DWARVEN_013";"Thatthil"; +"NAMESET_DWARVEN_014";"Olmul"; +"NAMESET_DWARVEN_015";"Comníth"; +"NAMESET_DWARVEN_016";"Erong"; +"NAMESET_DWARVEN_017";"Rërith"; +"NAMESET_DWARVEN_018";"Äkim"; +"NAMESET_DWARVEN_019";"Öntak"; +"NAMESET_DWARVEN_020";"Kitïg"; +"NAMESET_DWARVEN_021";"Thoth"; +"NAMESET_DWARVEN_022";"Tílgil"; +"NAMESET_DWARVEN_023";"Ingish"; +"NAMESET_DWARVEN_024";"Alak"; +"NAMESET_DWARVEN_025";"Egdoth"; +"NAMESET_DWARVEN_026";"Ùst"; +"NAMESET_DWARVEN_027";"Rimtar"; +"NAMESET_DWARVEN_028";"Bugsud"; +"NAMESET_DWARVEN_029";"Selsten"; +"NAMESET_DWARVEN_030";"Âtrid"; +"NAMESET_DWARVEN_031";"Roder"; +"NAMESET_DWARVEN_032";"Othsin"; +"NAMESET_DWARVEN_033";"Enôr"; +"NAMESET_DWARVEN_034";"Fer"; +"NAMESET_DWARVEN_035";"Dolush"; +"NAMESET_DWARVEN_036";"Ermis"; +"NAMESET_DWARVEN_037";"Åblel"; +"NAMESET_DWARVEN_038";"Agêk"; +"NAMESET_DWARVEN_039";"Ucat"; +"NAMESET_DWARVEN_040";"Ethbesh"; +"NAMESET_DWARVEN_041";"Nïng"; +"NAMESET_DWARVEN_042";"Emär"; +"NAMESET_DWARVEN_043";"Shalig"; +"NAMESET_DWARVEN_044";"Suthmam"; +"NAMESET_DWARVEN_045";"Ugath"; +"NAMESET_DWARVEN_046";"Udir"; +"NAMESET_DWARVEN_047";"Bemòng"; +"NAMESET_DWARVEN_048";"Tegir"; +"NAMESET_DWARVEN_049";"Nug"; +"NAMESET_DWARVEN_050";"Dudgoth"; +"NAMESET_DWARVEN_051";"Ogîk"; +"NAMESET_DWARVEN_052";"Robek"; +"NAMESET_DWARVEN_053";"Ilush"; +"NAMESET_DWARVEN_054";"Berim"; +"NAMESET_DWARVEN_055";"Emuth"; +"NAMESET_DWARVEN_056";"Sedil"; +"NAMESET_DWARVEN_057";"Izeg"; +"NAMESET_DWARVEN_058";"Okab"; +"NAMESET_DWARVEN_059";"Anam"; +"NAMESET_DWARVEN_060";"Girtol"; +"NAMESET_DWARVEN_061";"Etäg"; +"NAMESET_DWARVEN_062";"Stalkòb"; +"NAMESET_DWARVEN_063";"Enir"; +"NAMESET_DWARVEN_064";"Tosid"; +"NAMESET_DWARVEN_065";"Ím"; +"NAMESET_DWARVEN_066";"Lisig"; +"NAMESET_DWARVEN_067";"Stal"; +"NAMESET_DWARVEN_068";"Mafol"; +"NAMESET_DWARVEN_069";"Onshen"; +"NAMESET_DWARVEN_070";"Äs"; +"NAMESET_DWARVEN_071";"Sidos"; +"NAMESET_DWARVEN_072";"Sid"; +"NAMESET_DWARVEN_073";"Thîkut"; +"NAMESET_DWARVEN_074";"Gòstang"; +"NAMESET_DWARVEN_075";"Idek"; +"NAMESET_DWARVEN_076";"Themor"; +"NAMESET_DWARVEN_077";"Lurak"; +"NAMESET_DWARVEN_078";"Gost"; +"NAMESET_DWARVEN_079";"Namàsh"; +"NAMESET_DWARVEN_080";"Alåth"; +"NAMESET_DWARVEN_081";"Libash"; +"NAMESET_DWARVEN_082";"Dënush"; +"NAMESET_DWARVEN_083";"Biban"; +"NAMESET_DWARVEN_084";"Onlìl"; +"NAMESET_DWARVEN_085";"Lokast"; +"NAMESET_DWARVEN_086";"Rozsed"; +"NAMESET_DWARVEN_087";"Utheg"; +"NAMESET_DWARVEN_088";"Shin"; +"NAMESET_DWARVEN_089";"Mokez"; +"NAMESET_DWARVEN_090";"Lanlar"; +"NAMESET_DWARVEN_091";"Ebsas"; +"NAMESET_DWARVEN_092";"Osod"; +"NAMESET_DWARVEN_093";"Mabdug"; +"NAMESET_DWARVEN_094";"Ibruk"; +"NAMESET_DWARVEN_095";"Murak"; +"NAMESET_DWARVEN_096";"Cös"; +"NAMESET_DWARVEN_097";"Olom"; +"NAMESET_DWARVEN_098";"Kiror"; +"NAMESET_DWARVEN_099";"Kâkdal"; +"NAMESET_DWARVEN_100";"Zustash"; +"NAMESET_DWARVEN_101";"Okon"; +"NAMESET_DWARVEN_102";"Gatal"; +"NAMESET_DWARVEN_103";"Nazush"; +"NAMESET_DWARVEN_104";"Kun"; +"NAMESET_DWARVEN_105";"Nokzam"; +"NAMESET_DWARVEN_106";"Ëlot"; +"NAMESET_DWARVEN_107";"Stumäm"; +"NAMESET_DWARVEN_108";"Setnek"; +"NAMESET_DWARVEN_109";"Nural"; +"NAMESET_DWARVEN_110";"Tarmid"; +"NAMESET_DWARVEN_111";"Lek"; +"NAMESET_DWARVEN_112";"Cog"; +"NAMESET_DWARVEN_113";"Sákrith"; +"NAMESET_DWARVEN_114";"Ugog"; +"NAMESET_DWARVEN_115";"Ustos"; +"NAMESET_DWARVEN_116";"Thos"; +"NAMESET_DWARVEN_117";"Kovath"; +"NAMESET_DWARVEN_118";"Idos"; +"NAMESET_DWARVEN_119";"Nel"; +"NAMESET_DWARVEN_120";"Tobul"; +"NAMESET_DWARVEN_121";"Nashon"; +"NAMESET_DWARVEN_122";"Nicol"; +"NAMESET_DWARVEN_123";"Uvel"; +"NAMESET_DWARVEN_124";"Rorul"; +"NAMESET_DWARVEN_125";"Gasol"; +"NAMESET_DWARVEN_126";"Osed"; +"NAMESET_DWARVEN_127";"Lakish"; +"NAMESET_DWARVEN_128";"Okag"; diff --git a/assets/locales/nameset_exotic_deities.csv b/assets/locales/nameset_exotic_deities.csv new file mode 100644 index 000000000..827edd936 --- /dev/null +++ b/assets/locales/nameset_exotic_deities.csv @@ -0,0 +1,6 @@ +# Nameset - Fictional, used for deity names +# Mostly randomly generated, plus: +# References for mass media -- are allowed, as long as it does not impose copyright infringement + +"HEADER";"LatinAlph";"HangulKoKR";"KanaJaJP";"CyrilRuRU";"AlphElGR";"HanziZhCN";"HanziZhTW";"AksonThTH";"AlefbetHeIL";"Reference" +"NAMESET_DEITIES_001";"Armok";;;;;;;;"From game series Slaves to Armok: God of Blood" \ No newline at end of file diff --git a/assets/locales/nameset_scandinavian_f.csv b/assets/locales/nameset_scandinavian_f.csv index 280904d18..d98d2d513 100644 --- a/assets/locales/nameset_scandinavian_f.csv +++ b/assets/locales/nameset_scandinavian_f.csv @@ -1,6 +1,11 @@ # Nameset - Scandinavian # Data taken from www.behindthename.com -# Translator note: this nameset does not contain name that has [ɹ](american english 'r') sound (except '-er'). i.e. for Korean, 'Carl' should be '카를', 'Aleksander' should be '알렉산더'. + +# Each column stands for the writing system: +# LatinAlph - Latin Alphabet; HangulKoKR - Hangul, Korean; CyrilRuRU - Cyrillic, Russian; etc. + +# Translator note: this nameset does not contain name that has [ɹ](american english 'r') sound +# (except '-er'). i.e. for Korean, 'Carl' should be '카를', 'Aleksander' should be '알렉산더'. "HEADER";"LatinAlph";"HangulKoKR";"KanaJaJP";"CyrilRuRU";"AlphElGR";"HanziZhCN";"HanziZhTW";"AksonThTH";"AlefbetHeIL" "NAMESET_SCAN_F_001";"Agnes";"아그네스"; diff --git a/assets/locales/tiles.csv b/assets/locales/tiles.csv index 1e0d36685..403399005 100644 --- a/assets/locales/tiles.csv +++ b/assets/locales/tiles.csv @@ -1,3 +1,8 @@ +THIS IS UNUSED AND SHOULD BE REMOVED + + + + "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" "TILE_STONE";;"Stone";"Roche";;;;;;;;;;;;;;;;;;"돌"; diff --git a/assets/modules/LoadOrder.csv b/assets/modules/LoadOrder.csv index c7cc161b3..e7eee8dd7 100644 --- a/assets/modules/LoadOrder.csv +++ b/assets/modules/LoadOrder.csv @@ -6,4 +6,4 @@ # module_name,description_in_English_no_comma,(external Jar 1);(external Jar 2); ... basegame,The base game, -dwarventech,Logic gates and machines, +dwarventech,Dwarven technicians are emerged, diff --git a/assets/modules/basegame/materialprop.csv b/assets/modules/basegame/materialprop.csv index 99510e2b3..d0bf2cb1c 100644 --- a/assets/modules/basegame/materialprop.csv +++ b/assets/modules/basegame/materialprop.csv @@ -1,10 +1,15 @@ -"idst";"forcemod";"comments" -"rock"; "1"; -"cupr"; "2"; -"egls"; "4";"elven glass" -"iron"; "5"; -"argn"; "9";"argentum" -"stal"; "14";"steel" -"eaur"; "21";"elven aurichalcum" -"tial"; "33";"titanium alloy" -"admt"; "71";"adamant metal" +"idst";"forcemod";"endurance";"comments" +"rock"; "1"; "0.42"; +"cupr"; "2"; "1.00";"copper" +"egls"; "4"; "0.82";"elven glass" +"iron"; "5"; "1.42"; +"argn"; "9"; "0.91";"argentum/silver" +"stal"; "14"; "1.73";"steel" +"eaur"; "21"; "1.36";"elven aurichalcum" +"tial"; "33"; "2.16";"titanium alloy" +"admt"; "71"; "3.42";"adamant" + +# forcemod: related to attack points +# Attack points = `4 * forcemod.sqrt()` for each strike + +# endurance: multiplier, using copper as reference; determines durability of tools/weapons/armours/etc. diff --git a/src/net/torvald/colourutil/ColourTemp.kt b/src/net/torvald/colourutil/ColourTemp.kt index e97bc9a55..465207490 100644 --- a/src/net/torvald/colourutil/ColourTemp.kt +++ b/src/net/torvald/colourutil/ColourTemp.kt @@ -8,11 +8,11 @@ import net.torvald.colourutil.CIEXYZUtil.toColor import net.torvald.terrarum.ModMgr /** - * RGB-modeled CCT calculator + * RGB- and CIE-Modeled CCT calculator * Created by minjaesong on 16-07-26. */ object ColourTemp { - private var envOverlayColourmap = Image(ModMgr.getPath("basegame", "colourmap/black_body_col_1000_40000_K.tga")) + private var clut = Image(ModMgr.getPath("basegame", "colourmap/black_body_col_1000_40000_K.tga")) private fun colTempToImagePos(K: Int): Int { if (K < 1000 || K >= 40000) throw IllegalArgumentException("K: out of range. ($K)") @@ -21,7 +21,7 @@ object ColourTemp { /** returns sRGB-normalised colour */ operator fun invoke(temp: Int): Color = - envOverlayColourmap.getPixel(colTempToImagePos(temp), 0).toColor() + clut.getPixel(colTempToImagePos(temp), 0).toColor() /** returns CIExyY-based colour converted to slick.color * @param CIE_Y 0.0 - 1.0+ */ diff --git a/src/net/torvald/terrarum/CircularArray.kt b/src/net/torvald/dataclass/CircularArray.kt similarity index 98% rename from src/net/torvald/terrarum/CircularArray.kt rename to src/net/torvald/dataclass/CircularArray.kt index a84ce0777..0f735c2d7 100644 --- a/src/net/torvald/terrarum/CircularArray.kt +++ b/src/net/torvald/dataclass/CircularArray.kt @@ -1,4 +1,4 @@ -package net.torvald.terrarum +package net.torvald.dataclass /** diff --git a/src/net/torvald/terrarum/DefaultConfig.kt b/src/net/torvald/terrarum/DefaultConfig.kt index 7fce50326..51b505beb 100644 --- a/src/net/torvald/terrarum/DefaultConfig.kt +++ b/src/net/torvald/terrarum/DefaultConfig.kt @@ -75,6 +75,10 @@ object DefaultConfig { jsonObject.addProperty("safetywarning", true) + jsonObject.addProperty("maxparticles", 768) + + + return jsonObject } } diff --git a/src/net/torvald/terrarum/StateGraphicComputerTest.kt b/src/net/torvald/terrarum/StateGraphicComputerTest.kt index 7ab287fbb..81af58603 100644 --- a/src/net/torvald/terrarum/StateGraphicComputerTest.kt +++ b/src/net/torvald/terrarum/StateGraphicComputerTest.kt @@ -1,7 +1,7 @@ package net.torvald.terrarum import net.torvald.random.HQRNG -import net.torvald.terrarum.Terrarum.UPDATE_DELTA +import net.torvald.terrarum.Terrarum.delta import net.torvald.terrarum.gameactors.roundInt import net.torvald.terrarum.virtualcomputer.computer.TerrarumComputer import net.torvald.terrarum.virtualcomputer.peripheral.PeripheralVideoCard @@ -90,7 +90,7 @@ class StateGraphicComputerTest : BasicGameState() { var angle = 0.0 override fun update(container: GameContainer, game: StateBasedGame?, delta: Int) { - UPDATE_DELTA = delta + Terrarum.delta = delta Terrarum.appgc.setTitle("VT — F: ${container.fps}" + " — M: ${Terrarum.memInUse}M / ${Terrarum.memTotal}M / ${Terrarum.memXmx}M" + diff --git a/src/net/torvald/terrarum/StateInGame.kt b/src/net/torvald/terrarum/StateInGame.kt index 3ac6e9e1e..1c695e61b 100644 --- a/src/net/torvald/terrarum/StateInGame.kt +++ b/src/net/torvald/terrarum/StateInGame.kt @@ -1,8 +1,9 @@ package net.torvald.terrarum +import net.torvald.dataclass.CircularArray import net.torvald.imagefont.GameFontBase import net.torvald.random.HQRNG -import net.torvald.terrarum.Terrarum.UPDATE_DELTA +import net.torvald.terrarum.Terrarum.delta import net.torvald.terrarum.audio.AudioResourceLibrary import net.torvald.terrarum.concurrent.ThreadParallel import net.torvald.terrarum.console.* @@ -40,6 +41,7 @@ import java.lang.management.ManagementFactory import java.util.* import java.util.concurrent.locks.Lock import java.util.concurrent.locks.ReentrantLock +import javax.swing.JOptionPane import kotlin.collections.HashMap /** @@ -48,15 +50,13 @@ import kotlin.collections.HashMap class StateInGame : BasicGameState() { private val ACTOR_UPDATE_RANGE = 4096 - internal var game_mode = 0 - lateinit var world: GameWorld /** * list of Actors that is sorted by Actors' referenceID */ - val ACTORCONTAINER_INITIAL_SIZE = 128 - val PARTICLES_MAX = 768 + val ACTORCONTAINER_INITIAL_SIZE = 64 + val PARTICLES_MAX = Terrarum.getConfigInt("maxparticles") val actorContainer = ArrayList(ACTORCONTAINER_INITIAL_SIZE) val actorContainerInactive = ArrayList(ACTORCONTAINER_INITIAL_SIZE) val particlesContainer = CircularArray(PARTICLES_MAX) @@ -67,11 +67,6 @@ class StateInGame : BasicGameState() { private val actorsRenderMidTop = ArrayList(ACTORCONTAINER_INITIAL_SIZE) private val actorsRenderFront = ArrayList(ACTORCONTAINER_INITIAL_SIZE) - lateinit var consoleHandler: UIHandler - lateinit var debugWindow: UIHandler - lateinit var notifier: UIHandler - - var playableActorDelegate: PlayableActorDelegate? = null // DO NOT LATEINIT! private set internal val player: ActorHumanoid? // currently POSSESSED actor :) @@ -95,7 +90,12 @@ class StateInGame : BasicGameState() { val KEY_LIGHTMAP_RENDER = Key.F7 val KEY_LIGHTMAP_SMOOTH = Key.F8 - // UI aliases (no pause) + + + lateinit var consoleHandler: UIHandler + lateinit var debugWindow: UIHandler + lateinit var notifier: UIHandler + lateinit var uiPieMenu: UIHandler lateinit var uiQuickBar: UIHandler lateinit var uiInventoryPlayer: UIHandler @@ -103,10 +103,12 @@ class StateInGame : BasicGameState() { lateinit var uiVitalPrimary: UIHandler lateinit var uiVitalSecondary: UIHandler lateinit var uiVitalItem: UIHandler // itemcount/durability of held block or active ammo of held gun. As for the block, max value is 500. - lateinit var uiAliases: Array - // UI aliases (pause) - val uiAlasesPausing = ArrayList() + // UI aliases + lateinit var uiAliases: ArrayList + private set + lateinit var uiAlasesPausing: ArrayList + private set var paused: Boolean = false get() = uiAlasesPausing.map { if (it.isOpened) 1 else 0 }.sum() > 0 @@ -212,7 +214,7 @@ class StateInGame : BasicGameState() { // batch-process uiAliases - uiAliases = arrayOf( + uiAliases = arrayListOf( uiPieMenu, uiQuickBar, uiInventoryPlayer, @@ -221,6 +223,9 @@ class StateInGame : BasicGameState() { uiVitalSecondary, uiVitalItem ) + uiAlasesPausing = arrayListOf( + consoleHandler + ) uiAlasesPausing.forEach { uiContainer.add(it) } // put them all to the UIContainer uiAliases.forEach { uiContainer.add(it) } // put them all to the UIContainer @@ -238,7 +243,7 @@ class StateInGame : BasicGameState() { override fun update(gc: GameContainer, sbg: StateBasedGame, delta: Int) { particlesActive = 0 - UPDATE_DELTA = delta + Terrarum.delta = delta setAppTitle() @@ -337,7 +342,7 @@ class StateInGame : BasicGameState() { } playableActorDelegate = newActor - WorldSimulator(player, UPDATE_DELTA) + WorldSimulator(player, delta) } private fun changePossession(refid: Int) { @@ -352,7 +357,7 @@ class StateInGame : BasicGameState() { // accept new delegate playableActorDelegate = PlayableActorDelegate(getActorByID(refid) as ActorHumanoid) playableActorDelegate!!.actor.collisionType = ActorWithPhysics.COLLISION_KINEMATIC - WorldSimulator(player, UPDATE_DELTA) + WorldSimulator(player, delta) } private fun setAppTitle() { @@ -525,75 +530,15 @@ class StateInGame : BasicGameState() { } GameController.keyPressed(key, c) - - if (canPlayerControl) { - player?.keyPressed(key, c) - } - - if (Terrarum.getConfigIntArray("keyquickselalt").contains(key) - || key == Terrarum.getConfigInt("keyquicksel")) { - uiPieMenu.setAsOpen() - uiQuickBar.setAsClose() - } - - uiContainer.forEach { it.keyPressed(key, c) } // for KeyboardControlled UIcanvases - } - - override fun keyReleased(key: Int, c: Char) { - GameController.keyReleased(key, c) - - if (Terrarum.getConfigIntArray("keyquickselalt").contains(key) - || key == Terrarum.getConfigInt("keyquicksel")) { - uiPieMenu.setAsClose() - uiQuickBar.setAsOpen() - } - - uiContainer.forEach { it.keyReleased(key, c) } // for KeyboardControlled UIcanvases - } - - override fun mouseMoved(oldx: Int, oldy: Int, newx: Int, newy: Int) { - GameController.mouseMoved(oldx, oldy, newx, newy) - - uiContainer.forEach { it.mouseMoved(oldx, oldy, newx, newy) } // for MouseControlled UIcanvases - } - - override fun mouseDragged(oldx: Int, oldy: Int, newx: Int, newy: Int) { - GameController.mouseDragged(oldx, oldy, newx, newy) - - uiContainer.forEach { it.mouseDragged(oldx, oldy, newx, newy) } // for MouseControlled UIcanvases - } - - override fun mousePressed(button: Int, x: Int, y: Int) { - GameController.mousePressed(button, x, y) - - uiContainer.forEach { it.mousePressed(button, x, y) } // for MouseControlled UIcanvases - } - - override fun mouseReleased(button: Int, x: Int, y: Int) { - GameController.mouseReleased(button, x, y) - - uiContainer.forEach { it.mouseReleased(button, x, y) } // for MouseControlled UIcanvases - } - - override fun mouseWheelMoved(change: Int) { - GameController.mouseWheelMoved(change) - - uiContainer.forEach { it.mouseWheelMoved(change) } // for MouseControlled UIcanvases - } - - override fun controllerButtonPressed(controller: Int, button: Int) { - GameController.controllerButtonPressed(controller, button) - - uiContainer.forEach { it.controllerButtonPressed(controller, button) } // for GamepadControlled UIcanvases - - // TODO use item on Player - } - - override fun controllerButtonReleased(controller: Int, button: Int) { - GameController.controllerButtonReleased(controller, button) - - uiContainer.forEach { it.controllerButtonReleased(controller, button) } // for GamepadControlled UIcanvases } + override fun keyReleased(key: Int, c: Char) { GameController.keyReleased(key, c) } + override fun mouseMoved(oldx: Int, oldy: Int, newx: Int, newy: Int) { GameController.mouseMoved(oldx, oldy, newx, newy) } + override fun mouseDragged(oldx: Int, oldy: Int, newx: Int, newy: Int) { GameController.mouseDragged(oldx, oldy, newx, newy) } + override fun mousePressed(button: Int, x: Int, y: Int) { GameController.mousePressed(button, x, y) } + override fun mouseReleased(button: Int, x: Int, y: Int) { GameController.mouseReleased(button, x, y) } + override fun mouseWheelMoved(change: Int) { GameController.mouseWheelMoved(change) } + override fun controllerButtonPressed(controller: Int, button: Int) { GameController.controllerButtonPressed(controller, button) } + override fun controllerButtonReleased(controller: Int, button: Int) { GameController.controllerButtonReleased(controller, button) } override fun getID(): Int = Terrarum.STATE_ID_GAME @@ -858,8 +803,10 @@ class StateInGame : BasicGameState() { if (index < 0) { index = actorContainerInactive.binarySearch(ID) - if (index < 0) + if (index < 0) { + JOptionPane.showMessageDialog(null, "Actor with ID $ID does not exist.", null, JOptionPane.ERROR_MESSAGE) throw IllegalArgumentException("Actor with ID $ID does not exist.") + } else return actorContainerInactive[index] } diff --git a/src/net/torvald/terrarum/StateStutterTest.kt b/src/net/torvald/terrarum/StateStutterTest.kt new file mode 100644 index 000000000..2f962367c --- /dev/null +++ b/src/net/torvald/terrarum/StateStutterTest.kt @@ -0,0 +1,65 @@ +package net.torvald.terrarum + +import net.torvald.terrarum.gamecontroller.Key +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 + +/** + * Created by SKYHi14 on 2017-04-22. + */ +class StateStutterTest : BasicGameState() { + + private val testImage = Image(4096, 1728) + private val testImageG = testImage.graphics + + override fun init(container: GameContainer?, game: StateBasedGame?) { + } + + override fun update(container: GameContainer, game: StateBasedGame, delta: Int) { + Terrarum.appgc.setTitle("${Terrarum.NAME} — F: ${Terrarum.appgc.fps}") + + + if (container.input.isKeyDown(Key.UP)) + dy -= moveDelta + if (container.input.isKeyDown(Key.DOWN)) + dy += moveDelta + if (container.input.isKeyDown(Key.LEFT)) + dx -= moveDelta + if (container.input.isKeyDown(Key.RIGHT)) + dx += moveDelta + } + + override fun getID() = Terrarum.STATE_ID_TEST_REFRESHRATE + + private var imageMade = false + + private var moveDelta = 3 + private var dx = 0 + private var dy = 0 + + override fun render(container: GameContainer, game: StateBasedGame, g: Graphics) { + if (!imageMade) { + testImageG.font = Terrarum.fontGame + testImageG.color = Color.white + + (0x3400..0x9FFF).forEach { + testImageG.drawString( + "${it.toChar()}", + (it - 0x3400) % 256 * 16f, + (it - 0x3400) / 256 * 16f + ) + } + + testImageG.flush() + + imageMade = true + } + + g.translate(-dx.toFloat(), -dy.toFloat()) + g.drawImage(testImage, 0f, 0f) + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/StateUITest.kt b/src/net/torvald/terrarum/StateUITest.kt index 51f51383f..f1752a88a 100644 --- a/src/net/torvald/terrarum/StateUITest.kt +++ b/src/net/torvald/terrarum/StateUITest.kt @@ -47,7 +47,7 @@ class StateUITest : BasicGameState() { init { itemProperties[IVKey.ITEMTYPE] = IVKey.ItemType.HAMMER } - override val id: Int = 5656 + override var id: Int = 5656 override val isUnique: Boolean = true override var originalName: String = "Test tool" override var baseMass: Double = 12.0 @@ -63,7 +63,7 @@ class StateUITest : BasicGameState() { init { itemProperties[IVKey.ITEMTYPE] = IVKey.ItemType.ARTEFACT } - override val id: Int = 4633 + override var id: Int = 4633 override val isUnique: Boolean = true override var originalName: String = "CONTEXT_ITEM_QUEST_NOUN" override var baseMass: Double = 1.4 diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index 2b7f86061..ec60703e0 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -159,6 +159,7 @@ object Terrarum : StateBasedGame(GAME_NAME) { val STATE_ID_TEST_TTY = 0x102 val STATE_ID_TEST_BLUR = 0x103 val STATE_ID_TEST_SHADER = 0x104 + val STATE_ID_TEST_REFRESHRATE = 0x105 val STATE_ID_TEST_INPUT = 0x106 val STATE_ID_TEST_UI1 = 0x110 @@ -197,7 +198,7 @@ object Terrarum : StateBasedGame(GAME_NAME) { "${VERSION_RAW.ushr(24)}.${VERSION_RAW.and(0xFF0000).ushr(16)}.${VERSION_RAW.and(0xFFFF)}" const val NAME = "Terrarum" - var UPDATE_DELTA: Int = 0 + var delta: Int = 0 // these properties goes into the GameContainer @@ -332,6 +333,8 @@ object Terrarum : StateBasedGame(GAME_NAME) { //addState(StateControllerRumbleTest()) //addState(StateMidiInputTest()) //addState(StateNewRunesTest()) + //addState(StateStutterTest()) + ingame = StateInGame(); addState(ingame) diff --git a/src/net/torvald/terrarum/gameactors/ActorHumanoid.kt b/src/net/torvald/terrarum/gameactors/ActorHumanoid.kt index 87c2909d7..d95f0c088 100644 --- a/src/net/torvald/terrarum/gameactors/ActorHumanoid.kt +++ b/src/net/torvald/terrarum/gameactors/ActorHumanoid.kt @@ -138,7 +138,7 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null) private val nullItem = object : InventoryItem() { - override val id: Int = 0 + override var id: Int = 0 override val isUnique: Boolean = false override var baseMass: Double = 0.0 override var baseToolSize: Double? = null diff --git a/src/net/torvald/terrarum/gameactors/ActorInventory.kt b/src/net/torvald/terrarum/gameactors/ActorInventory.kt index d8d23dc57..756206320 100644 --- a/src/net/torvald/terrarum/gameactors/ActorInventory.kt +++ b/src/net/torvald/terrarum/gameactors/ActorInventory.kt @@ -44,12 +44,18 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode // If we already have the item, increment the amount // If not, add item with specified amount val existingItem = getByID(item.id) + if (existingItem != null) { // if the item already exists val newCount = getByID(item.id)!!.amount + count itemList.remove(existingItem) itemList.add(InventoryPair(existingItem.item, newCount)) } - else { + else { // new item + if (item.isDynamic) { + // assign new ID + item.originalID = item.id + item.id = InventoryItem.generateNewDynamicID(this) + } itemList.add(InventoryPair(item, count)) } insertionSortLastElem(itemList) @@ -121,12 +127,18 @@ class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode false - fun consumeItem(item: InventoryItem) { + fun consumeItem(actor: Actor, item: InventoryItem) { if (item.consumable) { remove(item, 1) } else { - item.durability -= 1f + val baseDamagePerSwing = if (actor is ActorHumanoid) + actor.avStrength / 1000.0 + else + 1.0 // TODO variable: scale, strength + val swingDmgToFrameDmg = Terrarum.delta.toDouble() / actor.actorValue.getAsDouble(AVKey.ACTION_INTERVAL)!! + + item.durability -= (baseDamagePerSwing * swingDmgToFrameDmg).toFloat() if (item.durability <= 0) remove(item, 1) } diff --git a/src/net/torvald/terrarum/gameactors/ActorWithPhysics.kt b/src/net/torvald/terrarum/gameactors/ActorWithPhysics.kt index a7fff1250..18e605af4 100644 --- a/src/net/torvald/terrarum/gameactors/ActorWithPhysics.kt +++ b/src/net/torvald/terrarum/gameactors/ActorWithPhysics.kt @@ -107,9 +107,9 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean } @Transient val MASS_LOWEST = 0.1 // Kilograms /** Apparent mass. Use "avBaseMass" for base mass */ - var mass: Double + val mass: Double get() = actorValue.getAsDouble(AVKey.BASEMASS) ?: MASS_DEFAULT * Math.pow(scale, 3.0) - set(value) { + /*set(value) { // use "var avBaseMass: Double" if (value <= 0) throw IllegalArgumentException("mass cannot be less than or equal to zero.") else if (value < MASS_LOWEST) { @@ -118,7 +118,7 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean } actorValue[AVKey.BASEMASS] = value / Math.pow(scale, 3.0) - } + }*/ @Transient private val MASS_DEFAULT: Double = 60.0 /** Valid range: [0, 1] */ var elasticity: Double = 0.0 @@ -232,7 +232,7 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean protected val gameContainer: GameContainer get() = Terrarum.appgc protected val updateDelta: Int - get() = Terrarum.UPDATE_DELTA + get() = Terrarum.delta /** * true: This actor had just made collision @@ -1286,15 +1286,12 @@ open class ActorWithPhysics(renderOrder: RenderOrder, val immobileBody: Boolean set(value) { actorValue[AVKey.SCALE] = value } - /** Apparent strength */ - var avStrength: Double - get() = (actorValue.getAsDouble(AVKey.STRENGTH) ?: 0.0) * - (actorValue.getAsDouble(AVKey.STRENGTHBUFF) ?: 0.0) * scale - set(value) { - actorValue[AVKey.STRENGTH] = - value / - ((actorValue.getAsDouble(AVKey.STRENGTHBUFF) ?: 1.0) * (avBaseStrength ?: 1.0)) - } + /** + * Apparent strength. 1 000 is default value + */ + val avStrength: Double + get() = (actorValue.getAsDouble(AVKey.STRENGTH) ?: 1000.0) * + (actorValue.getAsDouble(AVKey.STRENGTHBUFF) ?: 1.0) * scale var avBaseStrength: Double? get() = actorValue.getAsDouble(AVKey.STRENGTH) set(value) { diff --git a/src/net/torvald/terrarum/gameactors/DroppedItem.kt b/src/net/torvald/terrarum/gameactors/DroppedItem.kt index 57f4ae3f2..c6f29a495 100644 --- a/src/net/torvald/terrarum/gameactors/DroppedItem.kt +++ b/src/net/torvald/terrarum/gameactors/DroppedItem.kt @@ -17,7 +17,7 @@ class DroppedItem(private val item: InventoryItem) : ActorWithPhysics(Actor.Rend isVisible = true - mass = if (item.id < TileCodex.TILE_UNIQUE_MAX) + avBaseMass = if (item.id < TileCodex.TILE_UNIQUE_MAX) TileCodex[item.id].density / 1000.0 else ItemCodex[item.id].mass diff --git a/src/net/torvald/terrarum/gameactors/ParticleBase.kt b/src/net/torvald/terrarum/gameactors/ParticleBase.kt index 71208c9d6..b8383095e 100644 --- a/src/net/torvald/terrarum/gameactors/ParticleBase.kt +++ b/src/net/torvald/terrarum/gameactors/ParticleBase.kt @@ -20,7 +20,7 @@ open class ParticleBase(renderOrder: Actor.RenderOrder, maxLifeTime: Int? = null /** Will NOT actually delete from the CircularArray */ @Volatile var flagDespawn = false - override fun run() = update(Terrarum.appgc, Terrarum.UPDATE_DELTA) + override fun run() = update(Terrarum.appgc, Terrarum.delta) var isNoSubjectToGrav = false var dragCoefficient = 3.0 diff --git a/src/net/torvald/terrarum/gameactors/ParticleTestRain.kt b/src/net/torvald/terrarum/gameactors/ParticleTestRain.kt index 917a8d1c0..23661cd16 100644 --- a/src/net/torvald/terrarum/gameactors/ParticleTestRain.kt +++ b/src/net/torvald/terrarum/gameactors/ParticleTestRain.kt @@ -9,7 +9,7 @@ import org.newdawn.slick.Image class ParticleTestRain(posX: Double, posY: Double) : ParticleBase(Actor.RenderOrder.BEHIND, 6000) { init { - body = Image("./assets/graphics/weathers/raindrop.tga") + body = Image("./assets/modules/basegame/weathers/raindrop.tga") val w = body.width.toDouble() val h = body.height.toDouble() hitbox.setFromWidthHeight( diff --git a/src/net/torvald/terrarum/gameactors/PhysTestBall.kt b/src/net/torvald/terrarum/gameactors/PhysTestBall.kt index ef72e0168..144818f38 100644 --- a/src/net/torvald/terrarum/gameactors/PhysTestBall.kt +++ b/src/net/torvald/terrarum/gameactors/PhysTestBall.kt @@ -16,7 +16,7 @@ class PhysTestBall : ActorWithPhysics(Actor.RenderOrder.MIDDLE, immobileBody = t init { setHitboxDimension(16, 16, 0, 0) - mass = 10.0 + avBaseMass = 10.0 density = 200.0 color = RoguelikeRandomiser.composeColourFrom(RoguelikeRandomiser.POTION_PRIMARY_COLSET) diff --git a/src/net/torvald/terrarum/gameactors/Pocketed.kt b/src/net/torvald/terrarum/gameactors/Pocketed.kt index f2c1121c0..fd2a01eb5 100644 --- a/src/net/torvald/terrarum/gameactors/Pocketed.kt +++ b/src/net/torvald/terrarum/gameactors/Pocketed.kt @@ -25,7 +25,7 @@ interface Pocketed { } inventory.itemEquipped[item.equipPosition] = null - item.effectOnUnequip(Terrarum.appgc, Terrarum.UPDATE_DELTA) + item.effectOnUnequip(Terrarum.appgc, Terrarum.delta) } /** @@ -37,7 +37,7 @@ interface Pocketed { if (item.equipPosition >= 0) { inventory.itemEquipped[item.equipPosition] = item - item.effectWhenEquipped(Terrarum.appgc, Terrarum.UPDATE_DELTA) + item.effectWhenEquipped(Terrarum.appgc, Terrarum.delta) } } @@ -55,12 +55,13 @@ interface Pocketed { fun consumePrimary(item: InventoryItem) { - if (item.primaryUse(Terrarum.appgc, Terrarum.UPDATE_DELTA)) - inventory.consumeItem(item) // consume on successful + if (item.primaryUse(Terrarum.appgc, Terrarum.delta)) { + inventory.consumeItem(this as Actor, item) // consume on successful + } } fun consumeSecondary(item: InventoryItem) { - if (item.secondaryUse(Terrarum.appgc, Terrarum.UPDATE_DELTA)) - inventory.consumeItem(item) // consume on successful + if (item.secondaryUse(Terrarum.appgc, Terrarum.delta)) + inventory.consumeItem(this as Actor, item) // consume on successful } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/gamecontroller/GameController.kt b/src/net/torvald/terrarum/gamecontroller/GameController.kt index 89f88dbd8..91cc6256f 100644 --- a/src/net/torvald/terrarum/gamecontroller/GameController.kt +++ b/src/net/torvald/terrarum/gamecontroller/GameController.kt @@ -18,15 +18,17 @@ import org.newdawn.slick.Input */ object GameController { + private val ingame = Terrarum.ingame!! + // these four values can also be accessed with GameContainer. // e.g. gc.mouseTileX /** position of the mouse (pixelwise) relative to the world (also, currently pointing world-wise coordinate, if the world coordinate is pixel-wise) */ val mouseX: Float - get() = (MapCamera.x + Terrarum.appgc.input.mouseX / (Terrarum.ingame?.screenZoom ?: 1f)) + get() = (MapCamera.x + Terrarum.appgc.input.mouseX / (ingame.screenZoom ?: 1f)) /** position of the mouse (pixelwise) relative to the world (also, currently pointing world-wise coordinate, if the world coordinate is pixel-wise)*/ val mouseY: Float - get() = (MapCamera.y + Terrarum.appgc.input.mouseY / (Terrarum.ingame?.screenZoom ?: 1f)) + get() = (MapCamera.y + Terrarum.appgc.input.mouseY / (ingame.screenZoom ?: 1f)) /** currently pointing tile coordinate */ val mouseTileX: Int get() = (mouseX / FeaturesDrawer.TILE_SIZE).floorInt() @@ -35,81 +37,97 @@ object GameController { get() = (mouseY / FeaturesDrawer.TILE_SIZE).floorInt() fun processInput(gc: GameContainer, delta: Int, input: Input) { - if (Terrarum.ingame != null) { - val ingame = Terrarum.ingame!! - - - // actor process input - if (!ingame.consoleHandler.isTakingControl) { - if (ingame.canPlayerControl) { - ingame.actorContainer.forEach { - if (it is Controllable) { - // disable control of actor if the actor is riding something? - if ((it as ActorHumanoid).vehicleRiding != null) { - it.vehicleRiding!!.processInput(gc, delta, input) - } - else { - it.processInput(gc, delta, input) - } + // actor process input + if (!ingame.consoleHandler.isTakingControl) { + if (ingame.canPlayerControl) { + ingame.actorContainer.forEach { + if (it is Controllable) { + // disable control of actor if the actor is riding something? + if ((it as ActorHumanoid).vehicleRiding != null) { + it.vehicleRiding!!.processInput(gc, delta, input) + } + else { + it.processInput(gc, delta, input) } - } - } - else { - ingame.uiContainer.forEach { - it.processInput(gc, delta, input) } } } else { - ingame.consoleHandler.processInput(gc, delta, input) + ingame.uiContainer.forEach { + it.processInput(gc, delta, input) + } } + } + else { + ingame.consoleHandler.processInput(gc, delta, input) + } - /////////////////// - // MOUSE CONTROL // - /////////////////// + /////////////////// + // MOUSE CONTROL // + /////////////////// - // Use item: assuming the player has only one effective grip (EquipPosition.HAND_GRIP) - if (ingame.player != null && ingame.canPlayerControl) { - if (input.isMouseButtonDown(Terrarum.getConfigInt("mouseprimary")) || input.isMouseButtonDown(Terrarum.getConfigInt("mousesecondary"))) { - val itemOnGrip = ingame.player!!.inventory.itemEquipped[InventoryItem.EquipPosition.HAND_GRIP] + // Use item: assuming the player has only one effective grip (EquipPosition.HAND_GRIP) + if (ingame.player != null && ingame.canPlayerControl) { + if (input.isMouseButtonDown(Terrarum.getConfigInt("mouseprimary")) || input.isMouseButtonDown(Terrarum.getConfigInt("mousesecondary"))) { + val itemOnGrip = ingame.player!!.inventory.itemEquipped[InventoryItem.EquipPosition.HAND_GRIP] - if (itemOnGrip != null) { - if (input.isMouseButtonDown(Terrarum.getConfigInt("mouseprimary"))) { - ingame.player!!.consumePrimary(itemOnGrip) - } - if (input.isMouseButtonDown(Terrarum.getConfigInt("mousesecondary"))) { - ingame.player!!.consumeSecondary(itemOnGrip) - } + if (itemOnGrip != null) { + if (input.isMouseButtonDown(Terrarum.getConfigInt("mouseprimary"))) { + ingame.player!!.consumePrimary(itemOnGrip) + } + if (input.isMouseButtonDown(Terrarum.getConfigInt("mousesecondary"))) { + ingame.player!!.consumeSecondary(itemOnGrip) } } } - - - ///////////////////// - // GAMEPAD CONTROL // - ///////////////////// } + + + ///////////////////// + // GAMEPAD CONTROL // + ///////////////////// } fun keyPressed(key: Int, c: Char) { + + + + if (ingame.canPlayerControl) { + ingame.player?.keyPressed(key, c) + } + + if (Terrarum.getConfigIntArray("keyquickselalt").contains(key) + || key == Terrarum.getConfigInt("keyquicksel")) { + ingame.uiPieMenu.setAsOpen() + ingame.uiQuickBar.setAsClose() + } + + ingame.uiContainer.forEach { it.keyPressed(key, c) } // for KeyboardControlled UIcanvases } fun keyReleased(key: Int, c: Char) { + if (Terrarum.getConfigIntArray("keyquickselalt").contains(key) + || key == Terrarum.getConfigInt("keyquicksel")) { + ingame.uiPieMenu.setAsClose() + ingame.uiQuickBar.setAsOpen() + } + + ingame.uiContainer.forEach { it.keyReleased(key, c) } // for KeyboardControlled UIcanvases } fun mouseMoved(oldx: Int, oldy: Int, newx: Int, newy: Int) { - + ingame.uiContainer.forEach { it.mouseMoved(oldx, oldy, newx, newy) } // for MouseControlled UIcanvases } fun mouseDragged(oldx: Int, oldy: Int, newx: Int, newy: Int) { - + ingame.uiContainer.forEach { it.mouseDragged(oldx, oldy, newx, newy) } // for MouseControlled UIcanvases } fun mousePressed(button: Int, x: Int, y: Int) { - + ingame.uiContainer.forEach { it.mousePressed(button, x, y) } // for MouseControlled UIcanvases } fun mouseReleased(button: Int, x: Int, y: Int) { @@ -121,26 +139,29 @@ object GameController { if (itemOnGrip != null) { if (button == Terrarum.getConfigInt("mousePrimary")) { - itemOnGrip.endPrimaryUse(Terrarum.appgc, Terrarum.UPDATE_DELTA) + itemOnGrip.endPrimaryUse(Terrarum.appgc, Terrarum.delta) } if (button == Terrarum.getConfigInt("mouseSecondary")) { - itemOnGrip.endSecondaryUse(Terrarum.appgc, Terrarum.UPDATE_DELTA) + itemOnGrip.endSecondaryUse(Terrarum.appgc, Terrarum.delta) } } } + + + ingame.uiContainer.forEach { it.mouseReleased(button, x, y) } // for MouseControlled UIcanvases } } fun mouseWheelMoved(change: Int) { - + ingame.uiContainer.forEach { it.mouseWheelMoved(change) } // for MouseControlled UIcanvases } fun controllerButtonPressed(controller: Int, button: Int) { - + ingame.uiContainer.forEach { it.controllerButtonPressed(controller, button) } // for GamepadControlled UIcanvases } fun controllerButtonReleased(controller: Int, button: Int) { - + ingame.uiContainer.forEach { it.controllerButtonReleased(controller, button) } // for GamepadControlled UIcanvases } } diff --git a/src/net/torvald/terrarum/gameworld/GameWorld.kt b/src/net/torvald/terrarum/gameworld/GameWorld.kt index e6b1f47fa..2cbfc5300 100644 --- a/src/net/torvald/terrarum/gameworld/GameWorld.kt +++ b/src/net/torvald/terrarum/gameworld/GameWorld.kt @@ -225,6 +225,8 @@ class GameWorld(val width: Int, val height: Int) { fun inflctTerrainDamage(x: Int, y: Int, damage: Float): Boolean { val addr = LandUtil.getTileAddr(x, y) + //println("[GameWorld] ($x, $y) Damage: $damage") + if (terrainDamages[addr] == null) { // add new terrainDamages[addr] = damage } @@ -238,7 +240,7 @@ class GameWorld(val width: Int, val height: Int) { //println("[GameWorld] accumulated damage: ${terrainDamages[addr]}") // remove tile from the world - if (terrainDamages[addr]!! >= TileCodex[getTileFromTerrain(x, y)].strength) { + if (terrainDamages[addr] ?: 0f >= TileCodex[getTileFromTerrain(x, y)].strength) { setTileTerrain(x, y, 0) return true } diff --git a/src/net/torvald/terrarum/itemproperties/Calculate.kt b/src/net/torvald/terrarum/itemproperties/Calculate.kt index cca57367b..900539922 100644 --- a/src/net/torvald/terrarum/itemproperties/Calculate.kt +++ b/src/net/torvald/terrarum/itemproperties/Calculate.kt @@ -1,7 +1,6 @@ package net.torvald.terrarum.itemproperties -import net.torvald.terrarum.gameactors.roundInt -import net.torvald.terrarum.gameactors.sqrt +import net.torvald.terrarum.gameactors.* /** * Created by SKYHi14 on 2017-04-17. @@ -16,8 +15,8 @@ object Calculate { * * TODO Newtons as unit? */ - fun pickaxePower(material: Material): Float { - return 4f * material.forceMod.toFloat().sqrt() + fun pickaxePower(actor: ActorHumanoid, material: Material): Float { + return (4.0 * material.forceMod.toDouble().sqrt() * (actor.avStrength / 1000.0)).toFloat() } diff --git a/src/net/torvald/terrarum/itemproperties/InventoryItem.kt b/src/net/torvald/terrarum/itemproperties/InventoryItem.kt index 6c2e5acf7..d2fbcb161 100644 --- a/src/net/torvald/terrarum/itemproperties/InventoryItem.kt +++ b/src/net/torvald/terrarum/itemproperties/InventoryItem.kt @@ -1,6 +1,8 @@ package net.torvald.terrarum.itemproperties +import net.torvald.random.HQRNG import net.torvald.terrarum.ItemValue +import net.torvald.terrarum.gameactors.ActorInventory import net.torvald.terrarum.gameactors.Pocketed import net.torvald.terrarum.itemproperties.Material import net.torvald.terrarum.langpack.Lang @@ -12,7 +14,7 @@ import org.newdawn.slick.GameContainer */ abstract class InventoryItem : Comparable, Cloneable { - abstract val id: Int + abstract var id: Int /** * @@ -49,12 +51,23 @@ abstract class InventoryItem : Comparable, Cloneable { /** Single-use then destroyed (e.g. Tiles), aka negation of "stackable" */ abstract var consumable: Boolean + /** + * DYNAMIC means the item ID should be generated on the fly whenever the item is created. + * This is to be used with weapons/armours/etc where multiple instances can exist, and + * each of them should be treated as different item. + * + * ID Range: 32768..1048575 (ItemCodex.ITEM_DYNAMIC) + * + * The opposite of this is called STATIC and their example is a Block. + */ + open val isDynamic = false + /** * Where to equip the item */ - open var equipPosition: Int = EquipPosition.NULL + open val equipPosition: Int = EquipPosition.NULL - open var material: Material? = null + open val material: Material? = null /** * Apparent mass of the item. (basemass * scale^3) @@ -77,6 +90,7 @@ abstract class InventoryItem : Comparable, Cloneable { else throw NullPointerException("null input; nullify baseToolSize instead :p") } + var originalID = id /** * Scale of the item. @@ -226,4 +240,14 @@ abstract class InventoryItem : Comparable, Cloneable { return clonedItem } + + companion object { + fun generateNewDynamicID(inventory: ActorInventory): Int { + var ret: Int + do { + ret = HQRNG().nextInt(ItemCodex.ITEM_DYNAMIC.endInclusive + 1 - ItemCodex.ITEM_DYNAMIC.first) + ItemCodex.ITEM_DYNAMIC.first + } while (inventory.contains(ret)) + return ret + } + } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/itemproperties/ItemCodex.kt b/src/net/torvald/terrarum/itemproperties/ItemCodex.kt index 1b41f96a4..bb57a59fa 100644 --- a/src/net/torvald/terrarum/itemproperties/ItemCodex.kt +++ b/src/net/torvald/terrarum/itemproperties/ItemCodex.kt @@ -46,7 +46,7 @@ object ItemCodex { // tile items (blocks and walls are the same thing basically) for (i in ITEM_TILES + ITEM_WALLS) { itemCodex[i] = object : InventoryItem() { - override val id: Int = i + override var id: Int = i override val isUnique: Boolean = false override var baseMass: Double = TileCodex[i].density / 1000.0 override var baseToolSize: Double? = null @@ -54,6 +54,7 @@ object ItemCodex { override val originalName = TileCodex[i % ITEM_WALLS.first].nameKey override var consumable = true override var inventoryCategory = Category.BLOCK + override var isDynamic = true init { itemProperties[IVKey.ITEMTYPE] = if (i in ITEM_TILES) @@ -103,19 +104,19 @@ object ItemCodex { // test copper pickaxe itemCodex[ITEM_STATIC.first] = object : InventoryItem() { - override val id = ITEM_STATIC.first + override var id = ITEM_STATIC.first override val isUnique = false override val originalName = "Test Pick" override var baseMass = 10.0 override var baseToolSize: Double? = 10.0 override var consumable = false - override var maxDurability = 147//606 // this much tiles before breaking + override var maxDurability = 64//606 // this much tiles before breaking override var durability = maxDurability.toFloat() override var equipPosition = EquipPosition.HAND_GRIP override var inventoryCategory = Category.TOOL private val testmaterial = Material( - 0,0,0,0,0,0,0,0,14,0.0 // quick test material Steel + 0,0,0,0,0,0,0,0,1,0.0 // quick test material Stone ) init { @@ -131,6 +132,7 @@ object ItemCodex { using = true // linear search filter (check for intersection with tilewise mouse point and tilewise hitbox) + // return false if hitting actors Terrarum.ingame!!.actorContainer.forEach { if (it is ActorWithPhysics && it.tilewiseHitbox.intersects(mousePoint)) return false @@ -144,11 +146,12 @@ object ItemCodex { // filter passed, do the job val swingDmgToFrameDmg = delta.toDouble() / actorvalue.getAsDouble(AVKey.ACTION_INTERVAL)!! - return Terrarum.ingame!!.world.inflctTerrainDamage( + Terrarum.ingame!!.world.inflctTerrainDamage( gc.mouseTileX, gc.mouseTileY, - Calculate.pickaxePower(testmaterial) * swingDmgToFrameDmg.toFloat() + Calculate.pickaxePower(Terrarum.ingame!!.player!!, testmaterial) * swingDmgToFrameDmg.toFloat() ) + return true } override fun endPrimaryUse(gc: GameContainer, delta: Int): Boolean { @@ -164,6 +167,9 @@ object ItemCodex { // read from save (if applicable) and fill dynamicItemDescription } + /** + * Returns clone of the item in the Codex + */ operator fun get(code: Int): InventoryItem { if (code <= ITEM_STATIC.endInclusive) // generic item return itemCodex[code]!!.clone() // from CSV diff --git a/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralVideoCard.kt b/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralVideoCard.kt index c501fb308..3c7807f08 100644 --- a/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralVideoCard.kt +++ b/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralVideoCard.kt @@ -158,7 +158,7 @@ class PeripheralVideoCard(val host: TerrarumComputer, val termW: Int = 80, val t private val spriteBuffer = ImageBuffer(VSprite.width * 2, VSprite.height) fun render(g: Graphics) { - cursorBlinkTimer += Terrarum.UPDATE_DELTA + cursorBlinkTimer += Terrarum.delta if (cursorBlinkTimer > cursorBlinkTime) { cursorBlinkTimer -= cursorBlinkTime cursorBlinkOn = !cursorBlinkOn diff --git a/src/net/torvald/terrarum/weather/WeatherMixer.kt b/src/net/torvald/terrarum/weather/WeatherMixer.kt index 306b66289..75159eaac 100644 --- a/src/net/torvald/terrarum/weather/WeatherMixer.kt +++ b/src/net/torvald/terrarum/weather/WeatherMixer.kt @@ -151,7 +151,7 @@ object WeatherMixer { // interpolate R, G and B val scale = (timeInSec % dataPointDistance).toFloat() / dataPointDistance // [0.0, 1.0] - val newCol = CIELChabUtil.getGradient(scale, colourThis, colourNext) + val newCol = CIELabUtil.getGradient(scale, colourThis, colourNext) /* // very nice monitor code // 65 -> 66 | 300 | 19623 | RGB8(255, 0, 255) -[41%]-> RGB8(193, 97, 23) | * `230`40`160` diff --git a/GAME_SYSTEM.md b/work_files/GameDesign/BACKEND_DESIGN.md similarity index 100% rename from GAME_SYSTEM.md rename to work_files/GameDesign/BACKEND_DESIGN.md diff --git a/work_files/GameDesign/ECONOMY.md b/work_files/GameDesign/ECONOMY.md new file mode 100644 index 000000000..2d18df58f --- /dev/null +++ b/work_files/GameDesign/ECONOMY.md @@ -0,0 +1,14 @@ +## Economy ## + +Ref. How EVE Online's economy works and controlled + +* Mobs/People can be killed, and they drop resources: THEY PRINTS MONEY. +* If players die, some of (50 %?) their items are lost, forcing them to spend their money and resources. +* Items break, also forcing them to spend money (see below:) + +### Resource management ### + +* Tools/Weapons have durability + - And NOTHING IS INDESTRUCTIBLE (just cooldown time if they are "endgame" items, but not the weapon with highest damage -- see how Master Sword works in Zelda BotW) + - Relevant UIs are completed, so no turning back --Torvald, 2017-04-22 + diff --git a/ENVIRON.md b/work_files/GameDesign/ENVIRON.md similarity index 100% rename from ENVIRON.md rename to work_files/GameDesign/ENVIRON.md diff --git a/MISC_FEATURES.md b/work_files/GameDesign/MISC_FEATURES.md similarity index 100% rename from MISC_FEATURES.md rename to work_files/GameDesign/MISC_FEATURES.md diff --git a/MECHNANICS.md b/work_files/GameDesign/MISC_MECHNANICS.md similarity index 89% rename from MECHNANICS.md rename to work_files/GameDesign/MISC_MECHNANICS.md index 2e2403949..31b50eefb 100644 --- a/MECHNANICS.md +++ b/work_files/GameDesign/MISC_MECHNANICS.md @@ -42,13 +42,12 @@ Gemstones go elemental?! (pretty generic but otherwise there are no motivations ## Colouring ## -Natural: Use 4096 -Magical/Surreal: Use 24 Bits +Artificial: Use 4096 * Colouring of potion - Randomised, roguelike fashion - - Choose Col(R40, G40, B40) from set of finite cards: - 39, 39, 19, 19, 0, 0 + - Choose Col(RGB) from set of finite cards: + 255, 255, 128, 128, 0, 0 - MULTIPLY blend chosen colour with white texture @@ -146,15 +145,9 @@ see SAVE_FORMAT.md - Health: Regen per time - Magic: Out power per time - "I somewhat doubt this now..." --Torvald, 2017-03-12 + - "It won't work." --Torvald, 2017-04-22 -## Resource management ## - -* Tools/Weapons have durability - - And NOTHING IS INDESTRUCTIBLE (just cooldown time if they are "endgame" items, but not the weapon with highest damage -- see how Master Sword works in Zelda BotW) - - Hookshots are the exception! - - I was against it, but now I think it would make the game more playable --Torvald, 2017-03-12 - ## Civilisation ## diff --git a/work_files/Pickaxe Power.xlsx b/work_files/Pickaxe Power.xlsx index bc246eca23e8d830172101cd2b9327d11d53f5a6..6248c94b63f85ce1686f7679f88e22be7f64de76 100644 GIT binary patch delta 19940 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 YAgK5>NHhy5%{&bh7lWDka(?0d1Fx_X4*&oF delta 19647 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 Hx6uCpELl(+ diff --git a/work_files/dwarven_name_selector/dwarvenNameSelector.py b/work_files/dwarven_name_selector/dwarvenNameSelector.py new file mode 100644 index 000000000..221eb8bcc --- /dev/null +++ b/work_files/dwarven_name_selector/dwarvenNameSelector.py @@ -0,0 +1,21 @@ +from random import randint + +size = 128 + +names = [] +keys = range(1, size + 1) + + +with open("language_DWARF.txt") as f: + names = [line.rstrip('\n') for line in f] + + +for i in range(0, size): + r = randint(0, size - 1) + t = keys[i] + keys[i] = keys[r] + keys[r] = t + + +for i in range(0, size): + print('"NAMESET_DWARVEN_%03d";"%s";') % (i + 1, names[keys[i]]) diff --git a/work_files/dwarven_name_selector/language_DWARF.txt b/work_files/dwarven_name_selector/language_DWARF.txt new file mode 100644 index 000000000..29ab159e2 --- /dev/null +++ b/work_files/dwarven_name_selector/language_DWARF.txt @@ -0,0 +1,2195 @@ +Kulet +Alak +Bidok +Nicol +Anam +Gatal +Mabdug +Zustash +Sedil +Ustos +Emär +Izeg +Bemòng +Gost +Öntak +Tosid +Feb +Berim +Ibruk +Ermis +Thoth +Thatthil +Gòstang +Libash +Lakish +Asdos +Roder +Nel +Biban +Ugog +Ish +Robek +Olmul +Nokzam +Emuth +Fer +Uvel +Dolush +Agêk +Ucat +Ngárak +Enir +Ugath +Lisig +Etäg +Erong +Osed +Lanlar +Udir +Tarmid +Sákrith +Nural +Bugsud +Okag +Nazush +Nashon +Âtrid +Enôr +Dùstik +Kogan +Ingish +Dudgoth +Stalkòb +Themor +Murak +Alåth +Osod +Thîkut +Cog +Selsten +Egdoth +Othsin +Idek +Ùst +Suthmam +Ím +Okab +Onlìl +Gasol +Tegir +Namàsh +Noval +Shalig +Shin +Lek +Äkim +Kâkdal +Stumäm +Alud +Olom +Ëlot +Rozsed +Thos +Okon +Nïng +Ostar +Rorul +Kovath +Åblel +Stal +Girtol +Kitïg +Lokast +Reked +Comníth +Sidos +Setnek +Ethbesh +Nug +Mokez +Cös +Idos +Ogîk +Utheg +Tílgil +Ebsas +Lurak +Tobul +Ilush +Dënush +Rimtar +Kun +Äs +Kiror +Nicat +Onshen +Rërith +Mafol +Sid +Ìtdùn +Tilat +Îtat +Egot +Dib +Oril +Bukog +Atot +Imik +Sudir +Odshith +Rag +Dodók +Sinsot +Es +Dostob +Gast +Élmeth +Romlam +Avéd +Darål +Ân +Oddom +Zägel +Og +Shatag +Om +Gisëk +Balad +Nekik +Dakas +Dolek +Sog +Rafar +Laltur +Îkeng +Dan +Ozsit +Dunan +Uling +Dîbesh +Berath +Zangin +Shadkik +Innok +Vukcas +Metul +Than +Gesul +Ustir +Torish +Memrut +Usal +Ôm +Angrir +Cagith +Momuz +Zas +Deshlir +Astesh +Ôfid +Mothram +Rít +Nolthag +Matul +Irtir +Unul +Urist +Umom +Dëm +Lodel +Kodor +Alod +Nökor +Asen +Råsh +Ursas +Vakun +Thol +Kizbiz +Uthgúr +Ônor +Gar +Terstum +Zagith +Noshtath +Ub +Ùk +Amur +Minran +Idar +Rodnul +Nuggad +Okbod +Tun +Måmgoz +Fak +Ogon +Rëmrit +Stidest +Zag +Kosak +Sub +Shegum +Addor +Talin +Zin +Åmmeb +Sakub +Tig +Edir +Tath +Vesh +Etest +Atír +Lorsïth +Rir +Em +Deb +Shuthraz +Èshgor +Rùkal +Acöb +Okir +Arngish +Zilir +Im +Ïssun +Ilus +Gedor +Ramtak +Sombith +Ker +Lînem +Umid +Seth +Sogdol +Shis +Er +Odroz +Urem +Nist +Ódad +Lithrush +Zotir +Zikel +Zikâth +Stagshil +Atöl +Ók +Ziril +Uthar +Tatlosh +Ngitkar +Dur +Keshan +Ned +Eststek +Ar +Ëtul +Låluth +Totmon +Bem +Fenglel +Gigin +Atham +Amug +Cabnul +Nog +Fotthor +Ìltang +Dumed +Geshud +Inglaz +Ézneth +Tiklom +Ïsir +Eshim +Lumash +Gishdist +Thîdas +Enog +Dozeb +Muz +Âst +Dushig +Bakat +Shistat +Goral +Kèbmak +Inod +Zisur +List +Olon +Ërtong +Ngotol +Kolad +Egen +Rúbal +Gintar +Figul +Fikod +Bebmal +Bavast +Kåtdir +Éthes +Igest +Reg +Ubur +Belbez +Nòm +Bunsoth +Limul +Kurig +Ugzol +Erib +Îgam +Mas +Zugob +Mashus +Isin +Mondûl +Siz +Saràm +Dal +Omer +Sumun +Gommuk +Usith +Nerrid +Zágod +Mithmis +Enol +Munèst +Bol +Ûz +Bål +Sitheb +Duthnur +Ilbåd +Rurast +Suton +Nuglush +Ulthush +Razes +Bistök +Èzum +Nil +Ùnil +Otad +Oddet +Thetdel +Golud +Ûd +Kadol +Lur +Dumur +Aknûn +Otel +Ser +Zanor +Ur +Bokbon +Èfim +Shash +Zon +Obur +Banik +Sebïr +Lirlez +Erlin +Inen +Åmât +Goster +Kunon +Tarag +Kiron +Lilum +Oggez +Bom +Stetár +Sikel +Unnos +Kisul +Ikus +Sheget +Famthut +Rorung +Idor +Enur +Kur +Fokásh +Vostaz +Ushil +Gumùr +Ular +Enen +Goshîst +Âzkob +Meb +Likot +Stëtnin +Zarut +Nelzur +Datan +Tabmik +Rinal +Ebgok +Soshosh +Bukshon +Stîgil +Lumen +Maton +Abol +Cim +Egath +Imketh +Ilned +Zuden +Emtan +Edëm +Nosîm +Vagúsh +Alis +Etar +Inshot +Zasit +Arzes +Äbor +Oth +Vakist +Ner +Bul +Ìddor +Onam +Ulol +Toral +Omoth +Erar +Govos +Orab +Dalkam +Subol +Gomath +Cerol +Mingkil +Detthost +Rerik +Lolor +Os +Istam +Giken +Od +Mengmad +Âmid +Bungek +Zedot +Thak +Tetóth +Romek +Utir +Ïlul +Uleng +Sosmil +Aval +Lushòb +Asin +Vunom +Vurtib +Gukil +Dimol +Lelgas +Nethgön +Itur +Avan +Mingus +Aroth +Udos +Imust +Shàmman +Rinmol +Muzish +Kôn +Stul +Thash +Kenis +Fathkal +Inob +Igril +An +Unob +Nalthish +Ostësh +Kel +Eddaz +Ekur +Arâl +Shar +Rimuk +Ottan +Shagul +Ònul +Egeth +Sôd +Dusak +Ovus +Gomòk +Stesok +Vankåb +Ïlon +Odês +Alen +Bobrur +Stoling +Dum +Zagstok +Ol +Gatis +Udler +Adesh +Usân +Kavud +Kirun +Shasad +Shoveth +Lathon +Um +Thubil +Egom +Ugith +Ngutug +Kez +Lärim +Ikûl +Semtom +Kib +Rotik +Ir +Stosêth +Kezol +Anan +Disuth +Rîthol +Tezul +Irol +Otam +Rodïm +Nunok +Umel +Ishlum +Kin +Mebzuth +Usib +Nar +Migrur +Egar +Dakon +Lod +Nir +Anön +Muved +Am +Vabôk +Ág +Ritas +Udril +Shigós +Dáthnes +Âgez +Mörul +Zulash +Logem +Abal +Kulin +Lerom +Gatin +Ul +Monom +Bisól +Ginok +Rumred +Ugeth +Thuveg +Gor +Damol +Elcur +Erok +Tok +Îm +Rèt +Shoner +Inrus +Mistêm +Midor +Nilgin +Merir +Nikuz +Kamuk +Enal +Zèler +Stibbom +Vildang +Arkoth +Lashëd +Kasith +Ngathsesh +Tashem +Besmar +Furgig +Nônub +Rushrul +Megob +Uvir +Ùshrir +Esrel +Bukèt +Nimak +Lestus +Fullut +Arkim +Imsal +Led +Unib +Ron +Udar +Borush +Detes +Umoz +Serkib +Vudthar +Razot +Atem +Ezuk +Vozbel +Toltot +När +Stukos +Ang +Nuden +Ikud +Memad +Eshik +Emgash +Tirist +Athel +Seng +Osdin +Ethram +Kamut +Locun +Selor +Igër +Id +Astås +Âbir +Mosus +Omthel +Odur +Istbar +Zodost +Dumat +Relon +Notlith +Suthån +Ilid +Tithleth +Kezar +Ast +Fath +Tölún +Nabid +Sibrek +Thining +Gasìs +Noglesh +Aroz +Tâmol +Nanul +Urrïth +Kikës +Askak +Kes +Abshoth +Ubas +Angish +Allas +Gembish +Urvad +Fel +Ingul +Nekut +Genlath +Shulmik +Lenod +Abras +Asol +Shethel +Urnût +Zursul +Othsal +Shedim +Arak +Tizöt +Taran +Bithit +Otik +Kerlîg +Lêned +Sodel +Ônam +Zuglar +Keskal +Nåst +Uvóth +Mîvid +Éth +Kafâsh +Ngumrash +Zokun +Eshom +Nesteth +Thebil +Ammesh +Ral +Reksas +Gesis +Osal +Anir +Nabreth +Dakäl +Rungak +Nekol +Anriz +Kosh +Noth +Tharnas +Gansit +Bàgoz +Bim +Themthir +Sakil +Tekmok +Rasuk +Gäzot +Tozör +Tob +Kal +Eshtân +Mezum +Umar +Zeber +Geles +Therleth +Tinan +Zekrim +Magel +Adur +Ezar +Bonun +Bûnem +Egur +Unol +Vod +Lal +Debish +Bushos +Lokum +Thortith +Omât +Sethal +Soshor +Thocit +Esesh +Lûrit +Ubal +Òstob +Lashid +Usur +Kob +Kigok +Bekom +Magak +Vës +Estrith +Gongith +Dugud +Zat +Nomal +Oltud +Savot +Vîr +Dustîk +Shìstsak +Risid +Deler +Aztong +Gïnon +Sholil +Ecut +Mëtin +Lam +Togal +Mot +Nîles +Nefast +Atith +Rêg +Emen +Äkig +Abod +Sat +Timad +Ibas +Othob +Fûbeg +Tunur +Idgag +Eb +Omshit +Ibes +Oceg +Akuth +Isram +Ad +Imgoz +Nis +Stot +Ögred +Sined +Tecàk +Subet +Urmim +Obash +Dastot +Udib +Enkos +Kesh +Kidet +Ob +Thilség +Asteb +Akmesh +Vim +Angzak +Gakit +Rëcus +Kurik +Unkíl +Mez +Erith +Kalur +Arros +Amud +Nobgost +Tan +Lïd +Ashok +Nod +Nin +Rakust +Melbil +Nol +Raz +Dostust +Tat +Stïvut +Sigun +Urdim +Kälán +Shelret +Ïggal +Rëdreg +Idräth +Datlad +Ilral +Borik +Meden +Vafig +Tízen +Dizesh +Kobem +Cavor +Shilràr +Segun +Messog +Bukith +Bufut +Nilim +Ingtak +Damor +Gim +Nob +Eknar +Mengib +Isrir +Ishëm +Ticek +Mer +Othâsh +Kôkdath +Distat +Nirur +Kiret +Thisrid +Vucar +Kizab +Tudrug +Sêgam +Amluth +Nozush +Mirstal +Zamoth +Bomik +Munsog +Razmer +Liruk +Geget +Zenon +Okol +Torir +Stodir +Ôggon +Tikis +Unos +Legon +Alnis +Ïkor +Tathtak +Lidod +Azin +Isden +Uker +Kussad +Nilun +Bamgûs +Adril +Koshmot +Âl +Umgush +Senel +Sital +Kil +Kol +Bomrek +Boket +Atil +Iklist +Volal +Lish +Omrist +Ud +Fesh +Akath +Lim +Damîd +Anur +Kulal +Lolum +Ducim +Vesrul +Urosh +Akith +Lêrush +Ethír +Îd +Budam +Inol +Okang +Ging +Rilem +Kizest +Kebösh +Shesam +Ber +Zan +Zust +Enshal +Nastid +Ultèr +Ag +Zareth +Tislam +Doren +Róth +Nåzom +Akrul +Gusil +Kilrud +Lolok +Lemlor +Ivom +Fikuk +Gulgun +Kast +Usir +Sodzul +Stòkïd +Etas +Otil +Sosad +Nïr +Anban +Dithbish +Ekir +Onol +Godum +Lîlar +Ib +Etur +Rithul +Óboth +Al +Zimkel +Bimmon +Äkil +Tezad +Lâven +Sashas +Sezuk +Saneb +Kik +Dasnast +Itêg +Okil +Esis +Buris +Ecem +Kekath +Nas +Nursher +Limâr +Sostet +Ken +Estil +Oram +Galthor +Nefek +Gabet +Idok +Tetthush +Ukath +Igang +Ushul +Sil +Kar +Thur +Nitom +Azzin +Selen +Gadan +Osor +Thalal +Onesh +Guz +Êsik +Thestar +Astis +Ôtthat +Lisid +Nalish +Ozor +Ceshfot +Dok +Edos +Anzish +Lûk +Semor +Mulåsh +Âm +Kutam +Eges +Fimshel +Egul +Tesum +Cubor +Enseb +Idith +Edim +Vetek +Gérig +Lecad +Sterus +Umåm +Anil +Nobang +Atêsh +Umril +Milol +Rigòth +Èrith +Thazor +Gashcoz +Bor +Fôker +Megid +Elik +Tekkud +Olin +Ìrlom +Stemel +Inem +Lulâr +Zolak +Gärem +Gidur +Aban +Nebïn +Zasgim +Thólthod +Iden +Össek +Amkol +Löbor +Shùrrat +Kêdnath +Titthal +Stisträs +Tetist +Riras +Töras +Gekur +Gudos +Durad +Zêvut +Adil +Ngesgäs +Stettad +Shosêl +Udil +Litast +Arel +Otin +Vel +Avuz +Rithlut +Tomus +Dugan +Kalal +Shoshin +Eser +Îbmat +Kebul +Asiz +Almôsh +Rur +Rutod +Vumom +Orrun +Taron +Sárek +Ugosh +Esmul +Kisat +Il +Rinul +Mukar +Amkin +Mosos +Rith +Tòm +Bugud +Otung +Zoz +Umshad +Dasël +Lames +Lavath +Ozur +Zotthol +Nan +Rorash +Nguteg +Ôsust +Umäm +Instol +Kesting +Ebbus +Bobet +Ong +Zokgen +Räduk +Zunek +Kezat +Kadän +Sar +Êlbem +Ertal +Râmol +Girust +Nabas +Lozlok +Ongos +Shusug +Tongus +Tustzal +Kùgneb +Gamil +Gingim +Arin +Govûl +Vetor +Sharsid +Nakis +Lanir +Ikùl +Nakbab +Nimem +Numol +Urol +Atul +Deg +Onul +Ägash +Bogsosh +Ushang +Emal +Ethzuth +Gathil +Kebon +Sutung +Nizdast +Mimkot +Vir +Tumam +Osstam +Kulsim +Gemis +Êr +Fenok +Igrish +Urus +Rodem +Zengod +Íster +Luskal +Kìrar +Ilas +Anûz +Angen +Desis +Damèl +Assog +Usen +Babin +Tustem +Debben +Kabat +Âtast +Ebal +Lanzil +Belar +Solam +Ór +Nucam +Letom +Mengthul +Thêmnol +Linòn +Vuthil +Rersîr +Oltar +Domas +Asmel +Nish +Mamot +Nakuth +Udist +Ost +Shadust +Morus +Akrel +Kith +Bomel +Orngim +Ngubmul +Mat +Nulom +Ustan +Buzat +Thob +Tilesh +Gecast +Aran +Stëlmith +Dolil +Amem +Kasben +Fashuk +Ûbom +Mostod +Mangròd +Keng +Odkish +Roduk +Eggut +Bumal +Kurel +Kithìn +Nurom +Shomad +Doshet +Lål +Lun +Kugik +Tulon +Zoden +Nangês +Rifot +Kastar +Zefon +Kovest +Madush +Tårem +Shèrel +Goden +Birut +Shorast +Meng +Olthez +Litez +Mizês +Nonshut +Lårul +Tusung +Ullung +Minbaz +Zethruk +Kûbuk +Kivish +Rithog +Rabed +Rusest +Omtug +Stektob +Zimun +Num +Oslan +Mis +Salul +Langgud +Mugshith +Lòr +Mishthem +Sibnir +Zansong +Or +Est +Thistus +Bot +Aned +Absam +Vuzded +Emet +Luzat +Duthal +Cugshil +Shasar +Emdush +Shungmag +Zar +Luror +Manthul +Sholkik +Sankest +Othud +Ngithol +Udesh +Afen +Dast +Nothis +Îmäz +Sosh +Zalud +Geth +Udiz +Nitig +Ziksis +Midrim +Urthaz +Vuknud +Sïsal +Thum +Arösh +Guthstak +Asën +Neshast +Tenshed +Catten +Lêgan +Àlil +Nukad +Rakas +Bibar +Nitem +Vanel +Som +Gutid +Ros +Sestan +Ganad +Ardes +Tobot +Niral +Zavaz +Tellist +Umgan +Kesham +Azmol +Thokdeg +Dolok +Detgash +Zocuk +Gulnas +Arek +Rath +Ngotûn +Zocol +Evost +Lotol +Farash +Ruken +Enas +Isul +Miroth +Mor +Äsrath +Shed +Tabar +Lushût +Åm +Sut +Saruth +Ärged +Aral +Solon +Zulban +Stanïr +Lorbam +Såkzul +Kat +Teskom +Räm +Koshosh +Moldath +Ûlosh +Kúd +Masos +Fastam +Isan +Betan +Thibam +Elol +Uvar +Rul +Zaled +Esar +Kàs +Zìzcun +Vathem +Mïshak +Dubmen +Akam +Osram +Kuthdêng +Assar +Shizek +Mingtuth +Rafum +Omet +Merseth +Ós +Itnet +Gïsstir +Dalem +Ïdath +Gemsit +Ashzos +Enten +Nomes +Birir +Kukon +Âgoth +Ágesh +Dalzat +Tad +Mëlist +Ison +Rokel +Arceth +Rimad +Shigin +Kastol +Ruzos +Sharul +Omtäl +Eren +Sobìr +Noram +Dèg +Neth +Okin +Maskir +Dugal +Shagog +Shazak +Tinöth +Thir +Necak +Ital +Nulral +Ìnal +Gomóm +Vumshar +Borlon +Ngobol +Gireth +Okun +Rovol +Thulom +Kanzud +Lòråm +Rosat +Ottem +Duthtish +Thestkig +Thabost +Vúsh +Cuggán +Obok +Muthir +Rovod +Uzar +Kor +Amas +Ashmôn +Bisek +Zaneg +Gósmer +Zimesh +Bothon +Losis +Ildom +Azuz +Golast +Ednàd +Evon +Arom +Ninur +Conngim +Fongbez +Arrug +Avûsh +Rimís +Thokit +Agseth +Sharast +Bardum +Givel +Åm +Nikot +Arist +Sheced +Stin +Zoluth +Mestthos +Ineth +Amost +Oklit +Deduk +Mûthkat +Kosoth +Îgbit +Oshgât +Tazuk +Imbit +Bërûl +Sarvesh +Zuntîr +Sazir +Ekast +Desgir +Stâkud +Gonggash +Uzol +Moshnún +Urir +Geshak +Lektad +Akir +Zalìs +Teshkad +Kudust +Sastres +Becor +Noböt +Tokthat +Gishgil +Lândar +Karas +Etom +Thomal +Emad +Tangath +Ezost +Vath +Zakgol +Stibmer +Mìshos +Teling +Lased +Rintor +Îstlig +Tîrdug +Bab +Stingbol +Gethust +Maram +Nidòst +Bashnom +Ekzong +Thusest +Bocash +Dedros +Akur +Îcum +Etvuth +Tömud +Datur +Tishis +Lir +Darùd +Nugreth +Zim +Avum +Ishash +Tel +Ilrom +Unâl +Cilob +Ïngiz +Dakost +Kobel +Sheshek +Tolis +Gothum +Adek +Ibel +Lesast +Étol +Adas +Custith +Minkot +Îton +Sholèb +Degël +Uvash +Kumil +Fidgam +Lar +Stinthäd +Kemsor +Onrel +Sefol +Edzul +Nisgak +Dotir +Kàlreth +Alek +Resíl +Umstiz +Kêshshak +Sirab +Shaketh +Tatek +Isos +Ocîg +Atzul +Sebsúr +Odom +Arust +Götom +Sulus +Lensham +Geb +Ozon +Ngegdol +Storlut +Bekar +Gan +Zamnuth +Edtûl +Nolêth +Thabum +Astod +Ruthösh +Lisat +Zagug +Gudas +Sesh +Oshéb +Olil +Ustuth +Tholtig +Medtob +Asob +Gåkïz +Shem +Nadak +Nirmek +Imush +Kogsak +Ïteb +Dîshmab +Atîs +Tôsed +Kikrost +Ngalák +Takùth +Nunùr +Vukrig +Rerras +Arôl +Sosas +Rûl +Tholest +Tishak +Tharith +Vutram +Shotom +Ïlun +Râluk +Vosut +Sûbil +Ifin +Okosh +Zafal +Rulush +Gikut +Rem +Thikthog +Idash +Tathtat +Mesir +Lirér +Îlkeb +Adag +Isak +Kekim +Bâsen +Koman +Imesh +Shetbêth +Ulåb +Dogik +Rodim +Kathil +Öndin +Mekur +Enoz +Satneng +Rotig +Sofûsh +Asrer +Ozleb +Etath +Rumad +Esäst +Suvas +Bal +Oshot +Stelid +Med +Inir +Sîbosh +Lunrud +Olum +Shuk +Ôler +Stizash +Gusgash +Ïtsas +Edan +Ked +Ungèg +Merrang +Gudid +Kashez +Amal +Athnîr +Shithath +Istik +Akmam +Timnär +Elis +Kan +Lelum +Othil +Othôs +Nentuk +Dural +Salir +Kulbet +Fazís +Thikén +Ûlmush +Mishar +Tastrod +Todör +Ostath +Thasdoth +Belal +Ston +Ríbar +Tunom +Kudar +Gébar +Nothok +Libad +Gemur +Elbel +Ennol +Amnek +Soloz +Musöd +Samam +Ethad +Eshon +Etóm +Èrnam +Kethil +Enam +Inush +Atol +Ösir +Vathez +Furàt +Kegeth +Cudïst +Laz +Kåtâk +Thedak +Lumnum +Ôsed +Orshar +Thad +Shan +Ellest +Odgúb +Inash +Stegëth +Zithis +Lerteth +Stistmig +Luslem +Sherik +Zukthist +Artob +Nëlas +Zes +Nêcik +Ûthir +Othlest +Ibesh +Fash +Anist +Òrdir +Rab +Orshet +Uzlir +Ginet +Eral +Ilash +Etnàr +Tomêm +Insél +Riril +Thimshur +Nokgol +Mözir +Igath +Gasir +Bubnus +Ïthod +Uthmik +Uben +Adbok +Ronush +Rikkir +Thiz +Lakàl +Rôber +Egast +Akgos +Zatam +Sholid +Akest +Thun +Gídthur +Immast +Sanreb +Mïkstal +Vudnis +Estun +Ozkak +Åkum +Kacoth +Etost +Arban +Kurol +Agsal +Rethal +Oshur +Vathsith +Bithsêst +Kezkíg +Kir +Shadmal +Ádol +Ablish +Shislug +Zutshosh +Ogtum +Batôk +Izkil +Ireg +Ushlub +Deleth +Thetust +Stigaz +Ethab +Emäth +Konad +Shukar +Idrom +Gubel +Egeb +Astel +Boshut +Uzan +Ranzar +Rîsen +Nakas +Gatiz +Erush +Shameb +Ushesh +Katthir +Íkthag +Rìthar +Sizir +Tost +Alûth +Ator +Kadôl +Istrath +Shos +Ulzest +Kastaz +Kod +Etes +Nosing +Merig +Fushur +Avog +Othör +Midil +Fevil +Ittás +Bakust +Bëmbul +Duz +Zeg +Edól +Kifed +Thet +Ostuk +Endok +Ushat +Ukosh +Lebes +Limúr +Ód +Desor +Amith +Ilir +Ishol +Otsus +Mogshum +Ishen +Kíddir +Meban +Gúr +Rodum +Monang +Thosbut +Atêk +Edod +Astan +Tangak +Sacat +Dôbar +Komut +Dimshas +Olnen +Tathur +Evud +Oshosh +Orstist +Kab +Talul +Sokan +Nanir +Irid +Tögum +Asdûg +Mes +Nasod +Lemis +Stukón +Nanoth +Kokeb +Óruk +Zursùl +Mozib +Gorroth +Egståk +Asàs +Zalstom +Ikal +Esdor +Rilbet +Dezrem +Sebshos +Nebél +Gethor +Ralâth +Baros +Iseth +Cenäth +Leshal +Sanád +Rithzâm +Kordam +Roldeth +Ugut +Arbost +Sedish +Tadar +Azoth +Osresh +Eddud +Artum +Dallith +Siknug +Vashzud +Ngilok +Ilon +Ìlud +Gemesh +Rashgur +Mothdast +Dák +Thukkan +Alron +Ungòb +Útost +Bel +Sanus +Kithäl +Theb +Konos +Neb +Itred +Ecosh +Cegol +Luthoz +Thastith +Remang +Athser +Ngusham +Gingik +Rangab +Kontuth +Letmos +Mishim +Losush +Othbem +Bêngeng +Lasgan +Utal +Sedur +Engig +Sunggor +Thistun +Köshdes +Ngefel +Umer +Uleb +Náshas +Rômab +Sezom +Shashdon +Mëbnith +Kán +Gitnuk +Daros +Nokim +Mostib +Thethrus +Kagmel +Bidnoz +Elbost +Oten +Ushdish +Kitung +Nubam +Onget +Dëngstam +Nimar +Gelut +Nisûn +Tarem +Nam +Kozoth +Tokmek +Ed +Et +Thunen +Shokmug +Vutok +Zanos +Torad +Berdan +Nal +Mosol +Othduk +Kinem +Zatthud +Nabår +Rirnöl +Lised +Danman +Nirkún +Mubun +Lushôn +Kot +Ritan +Nóton +Turel +Cemosh +Dosîm +Musar +Misttar +Obot +Baktus +Tagùz +Mâtzang +Shoduk +Ronstiz +Ubbul +Zutthan +Oshnïl +Ushal +Ograd +Tumos +Korsid \ No newline at end of file