From aa914377feb7fa1290f12d726e1d8e2e659cad84 Mon Sep 17 00:00:00 2001 From: Song Minjae Date: Tue, 29 Mar 2016 13:15:03 +0900 Subject: [PATCH] Lightmap.get/MapLayer.get are now nullable, better overworld generator with Joise, still needs fix in the dirt layer part. Former-commit-id: 0a5fa31bab45d093771ca109adbeb9c07fb8e90e Former-commit-id: d8a2b5b77a36b6c742cf220b2d325895111c8f3a --- Known problems.md | 17 +- README.md | 17 +- res/graphics/sky_colour.png | Bin 16947 -> 16986 bytes res/locales/helpOnTheFly.csv | 20 +- res/raw/{ => creatures}/CreatureHuman.json | 0 .../{ => factions}/FactionGenericPlayer.json | 0 res/raw/{ => factions}/FactionSigrid.json | 0 .../FactionWildHamletTemplate.json | 0 src/com/Torvald/Terrarum/ABOUT | 130 ----- src/com/Torvald/Terrarum/COPYING | 6 - src/com/Torvald/Terrarum/Game.kt | 26 +- src/com/Torvald/Terrarum/GameMap/GameMap.kt | 34 +- src/com/Torvald/Terrarum/GameMap/MapLayer.kt | 14 +- .../Terrarum/GameMap/PairedMapLayer.kt | 18 +- src/com/Torvald/Terrarum/GameMap/WorldTime.kt | 10 +- src/com/Torvald/Terrarum/LangPack/Lang.kt | 11 +- src/com/Torvald/Terrarum/MECHNANICS | 112 ---- .../Terrarum/MapDrawer/LightmapRenderer.kt | 48 +- .../Torvald/Terrarum/MapDrawer/MapCamera.kt | 105 +--- .../Torvald/Terrarum/MapDrawer/MapDrawer.kt | 6 +- .../Terrarum/MapGenerator/MapGenerator.kt | 537 +++++++++++------- .../Terrarum/MapGenerator/SimplexNoise.kt | 4 +- src/com/Torvald/Terrarum/SAVE_FORMAT | 54 -- src/com/Torvald/Terrarum/Terrarum.kt | 8 +- .../Terrarum/TileProperties/TileNameCode.kt | 2 +- .../Terrarum/TileProperties/TilePropCodex.kt | 8 +- .../Terrarum/gameactors/ActorInventory.kt | 1 + .../Terrarum/gameactors/ActorWithBody.kt | 3 +- .../gameactors/CreatureRawInjector.kt | 3 +- .../Torvald/Terrarum/gameactors/PFSigrid.kt | 24 +- .../Terrarum/gameactors/faction/Faction.kt | 2 + src/com/jme3/math/FastMath.java | 3 +- src/com/torvald/terrarum/ABOUT.md | 132 +++++ src/com/torvald/terrarum/COPYING.md | 9 + src/com/torvald/terrarum/MECHNANICS.md | 125 ++++ src/com/torvald/terrarum/SAVE_FORMAT.md | 57 ++ src/com/torvald/terrarum/console/ExportMap.kt | 12 +- .../torvald/terrarum/console/GetFactioning.kt | 6 +- src/com/torvald/terrarum/console/Help.kt | 13 +- .../gameactors/faction/FactionFactory.kt} | 15 +- .../gameactors/scheduler/NPCSchedule.kt | 8 + .../terrarum/realestate/RealEstateCodex.kt | 27 + .../terrarum/realestate/RealEstateUtility.kt | 14 + .../tilestats/{TileStat.kt => TileStats.kt} | 6 +- .../terrarum/ui/BasicDebugInfoWindow.kt | 34 +- src/com/torvald/terrarum/ui/ConsoleWindow.kt | 2 +- src/com/torvald/terrarum/ui/MessageWindow.kt | 2 +- 47 files changed, 894 insertions(+), 791 deletions(-) rename res/raw/{ => creatures}/CreatureHuman.json (100%) rename res/raw/{ => factions}/FactionGenericPlayer.json (100%) rename res/raw/{ => factions}/FactionSigrid.json (100%) rename res/raw/{ => factions}/FactionWildHamletTemplate.json (100%) delete mode 100644 src/com/Torvald/Terrarum/ABOUT delete mode 100644 src/com/Torvald/Terrarum/COPYING delete mode 100644 src/com/Torvald/Terrarum/MECHNANICS delete mode 100644 src/com/Torvald/Terrarum/SAVE_FORMAT create mode 100644 src/com/torvald/terrarum/ABOUT.md create mode 100644 src/com/torvald/terrarum/COPYING.md create mode 100644 src/com/torvald/terrarum/MECHNANICS.md create mode 100644 src/com/torvald/terrarum/SAVE_FORMAT.md rename src/com/{Torvald/Terrarum/gameactors/faction/FactionRelatorFactory.kt => torvald/terrarum/gameactors/faction/FactionFactory.kt} (83%) create mode 100644 src/com/torvald/terrarum/gameactors/scheduler/NPCSchedule.kt create mode 100644 src/com/torvald/terrarum/realestate/RealEstateCodex.kt create mode 100644 src/com/torvald/terrarum/realestate/RealEstateUtility.kt rename src/com/torvald/terrarum/tilestats/{TileStat.kt => TileStats.kt} (95%) diff --git a/Known problems.md b/Known problems.md index ad1708001..d5c38fee8 100644 --- a/Known problems.md +++ b/Known problems.md @@ -1,16 +1,19 @@ -## From playtests ## +# Unresolved # ### Character ### - -* Cannot fit into single-tile width pit - Cause: Player/NPC looks slim enough to fit, but don't fit in the game - Solution: Draw them wider, allow them to fit into the pit (Phys resolver will glitch?) +* Arm behind the body seems unnatural -## Internal ## ### Phys ### * Actor stick to wall and not get off +* Actor with mass <2 behaves erratically -* Actor with mass <2 behaves erratically \ No newline at end of file + +# Resolved # + +* Cannot fit into single-tile width pit + Cause: Player/NPC looks slim enough to fit, but don't fit in the game + Solution: Draw them wider, allow them to fit into the pit (Phys resolver will glitch?) + __Solved__ — Player/NPC hitbox now have a width of 15 pixels. diff --git a/README.md b/README.md index 1f60ff60e..5fd96bb61 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,11 @@ Documentations and resources for work (such as .psd) are also included in the re Any contribution in this project must be made sorely in English, so be sure to use English in codes, comments, etc. ## Setup ## -* Configuration -Just make sure you have JDK 8 or higher + +* Requirements: + - JDK 8 or higher + - Working copy of IntelliJ IDEA from JetBrains s.r.o., community edition is okay to use. + * Required libraries are included in the repository. @@ -20,8 +23,8 @@ Just make sure you have JDK 8 or higher * Writing tests * Code review -* Guidelines -Quintessential: write code that even an imbecile can understand. +* Guidelines + - Quintessential: write code that even an imbecile can understand. ### Contributing translations ### @@ -42,10 +45,10 @@ Note: Right-to-left languages (arabic, hebrew, etc.) are not supported. ## 개요 ## -이 변변한 이름 없는 프로젝트는 사이드뷰 발판 게임 형식으로 더 친절한 〈드워프 포트리스〉의 모험가 모드를 지향하는 게임 제작 프로젝트입니다. 영구 사망, 무작위성, __넘쳐나는 재미__와 같이 로그라이크스러운 요소를 지닙니다. +이 변변한 이름 없는 프로젝트는 사이드뷰 발판 게임 형식으로 더 친절한 〈드워프 포트리스〉의 모험가 모드를 지향하는 게임 제작 프로젝트입니다. 영구 사망, 무작위성, __넘쳐나는 재미__와 같이 ‘로그라이크’스러운 요소를 지닙니다. -이 프로젝트는 주 언어로 코틀린, 자바를 사용하며 파이선·루아 등으로 작성된 툴을 이용합니다. +이 프로젝트는 주 언어로 코틀린·자바를 사용하며 파이선·루아 등으로 작성된 툴을 이용합니다. -문서와 작업용 리소스(psd 등) 또한 이 저장소에 포함되어 있습니다. gcx와 numbers 형식으로 된 문서를 읽고 수정하기 위해 맥 컴퓨터가 필요할 수 있습니다. +개발 문서와 작업용 리소스(psd 등) 또한 이 저장소에 포함되어 있습니다. gcx와 numbers 형식으로 된 문서를 읽고 수정하기 위해 맥 컴퓨터가 필요할 수 있습니다. 이 프로젝트에 대한 기여는 영어로 이루어져야 합니다. 따라서 코드나 주석 등을 작성할 때는 영어를 사용해 주십시오. \ No newline at end of file diff --git a/res/graphics/sky_colour.png b/res/graphics/sky_colour.png index ec6f98716594d9577376ac60c987ed955b3c5377..57fb26e8866026cf6bfa6badb43b73783a1990f2 100644 GIT binary patch delta 2537 zcma)6Yh2O?7p9!L&AC=~o0n|srX_hnFg0|o^z~9Y6|#kw<|R@~5``3%f2&nLr+Ep5 zNP#Uw^Ma&AgaTHU`if!Y1;NzH3kfQSilQdld;6{T+s>!wJm>jx&hz{Z=a)6|U)J2i z8GY`KaCY*5x_LmMB*5t4$L+KKYdL10#I4!s>I!j-i;al|L*m_>!LH7bc<@gLpzdHu z3@qN&#mU7b?lg=U>I7ytJ8QF=2=mfibsMgtCq)1G7!k}rB z%Cj6!EZ<88qG&92rtNI1r2-S=*Ehi>MqXXT^HT;Le(ZTP(%(e%5WN;cicnK*QYlWE z+0%as&pidmF1rx7t=>Xqk>@0NVJ?^H3rmC3a%H>qVKkQSHM}Fpj3B$JxMxlnnMONU z$g8zH3H>JAyFw??bkYhcSwC94-W72VYVT|lYIfDqAR;r7mFtqYiN(X91` zR_wb~S*C95`1x84kN1SIzz7tW@}`GuDaV0Uw>LldG^rK z9qNIdvQE@y`;QHT_7FvZfL&@gk$l5SQE`s)^i6L-+l3=m@DjcoHw1Qv7$Ngm%&_(v z>zAQNmqTOGxsH-dHb0h=-u;U&7omrv?DGdWArom+XJ-jFK<1bY3&Mz+{;{4~4eY*x#igLL_NU|Mo{*)acYWCE{XmcbiAFivx{d!tBj`sh zKacQGoKoZk*vmbI*-md&dBMBT!}br&tE|caTkQwl@?P!w>lyCm?+}L5la=zBsYc}r zL+~5<)%$P0c~I^oN*_#X4M#|2iZWBfW2id)FmpPSNF=m zESzfPBCVKpCDJ-7c)*Hh?^#frFf3t}HAO}$lC+KD*Go_V{IsG+q?vp@KAY%0ygROT zX6Bwv`1tYHJc*2N9xI|w1^c@xU_E>&Q+d-nExG<^*LaU&zz2UjI#g>M4Xn&$Hy5uZ z9fEHm{Qx%s0#1usa=&nCKlrdY4`TA~{fFk%MrpLOn4u5#elJm>rVmc9+#Lb1lCt#5 zbF}*M?dxdm$5Od2gFfK!LVU~d2+EgWl4lRH!`?P^6l+z)F1r3Zt-}|rlJ$=omYbIu z;)a5R5>oMMc=d{C zsUs5mwW6tOl2d0g`Pg!nS^ne2;o{L%xJE#4u4G^yLrh$NG+laSHDS|fhD+^OEF4O^FbWk1603&V8W8{=i85?))&~6!E=Kx~0c=UF1!bnyd z_gAw!RLhEo!I?*MO_CDV^}oVdM4!h)1vXp%iYo}@Rp4#-AO-HO{g?!S9_@)ao)ywx z&AUpLl7)!-D_L&X{)QDosU)pdD-;8$j#dYf5VdcTwWMExQB<%8`J@i=Zr0VI%(ZVHB_7I$POpgj1^}wIR*CJy~2v+o6ts_c?-Xy@7$Dcimym; zlAz-E-jC!3z~0+p23P2}CLZ^x5$cMK(^s+!ps_uIjU<|9N;4a zpS@k&Dw_HBfL+P{3`WDHE+@OZUbCBWDK*3F98G^l;vt&yAF-&HQ&$9*9_{8p# zoIZ8lYUh#;JF#djSIRh&7muRsVvM*i{o^bSlVDe`(T@dn(dqb@#mStr(XKO*m>!b^W(edFa7iieSHnfw4cO9Dr3yk{UN%xd~PTz-WVpiL>`9Sls= z>&w9tZMjoQpKOS0O%f?X=B2+h7)W^EN&P){LA0M>^2!+Z^1CDJS}RkXCqgm_Z-Cdc zXK5L2)Nz$FlbwUMG{?R;6}hQ1;d`|2s%NW8e#Wc$?NVX`L%*$kmZ)?BHkqgoguT#J zqYl|8*k}}5a+nj5A@lZx-6x)z4=m*iPuG&4zoW=i;LR*sL_`}Q{vb72ia)hOQ-jp+ z4{IxqbQ2ZJ?yABh%x_IfMEd|MengxjU7S?@D%mDC-i55oAHbbOb+Z6g&%`LQkL9Rl zqiPreIkK?|UCAd8hYb#~MxO|OOYCxo`iY|Wl#Obcz@%hKj>(EbX!SoAPV_KRhljXN u6jz2Xr(F2YNBiIHFRmLi{D}<)BTxf;x6K-NwYkl|X8t}wN9w*mb?Fard;Y)x delta 2497 zcma)6c~sJg7Pg%9l{3RDO{Yb9P1claxZtj%S&gGnxs|AB0+M?!s3`iIsh*BU#oRJd zWU7~%xFwq5f-R${nV8~$qEd-VASenVE-*9iy*a1(Z|=G0+@4BpL-hWfc}?Y6Y=@m|9s|qD-$MZNg3M zERkV0P)npW)W)v3c$dxJBZ_yq{5|3&4c^})`f56SB7sWOEQ5UJcfgNPY-MK-ba=SC z`le1Sk^&NhXZM}4jM!vqE$o+S*mtVVD@J=ops<=FQEIyib$E7r37Y=1K{-1OwSHDb zs0w$eeG<>je=HCAT6+LzQkr3e-kQWmSmcd4Z1iK~Kaw*dZ)0L>^rK!g`0JGv?kyLW zS@t@LD8NAIa6{EHQ$ZZAIC=*&p+g|4j=jQ4)3>ee0QOW*F2W?uZ(w>H^ zrk~62dfPB<+r8yVv@J+|)74cbUCZ;axLH}SF|{-y=sSEGlR$Ik9fie7n?drcU}^6Z z^Ga0&rH|(@|I4Bhf)#%*pH!p@;AgFkehq6en1Tae3<(2hf;1s%yRkHG20lF4!(cC6 zq$h$$@@9XLQB#&6gYU2KV&klZQ{Cn{v6Jod;$cKm+yb;S;P8|dOn`PGkBNkGW-f~c zhT)Gf`u>&p$jgIzRN;9sHQk-^a=)q0mnX(ON#DP?9H{l~y~YQ)W;ARWg^!JUKzgSy z2W;)NozaJ?igzGVDJDbTs;%=6eX*qEXsS)ltLLSU({4Wx6h9GlAI;BPR{sjB^ZZN< zU#i<={lfE_YU<%=&~gUb{s(Z zvTX}qRqu4z%nJ*tU5u8ru1-f8a0aKX?q4!3b-@_7&Jdz??1LQw9V6&h$%5gixxNvT*!<%(*w~6T&J>Ivh*tV&axT4LFASCoWY}d(NDbcZ)!^e}cgO znvipP{T1HtT-jugt=h}oJu@~J5CwoIe^laCbyZbInv1WC(rzcN*q5D;YdtCLVo@jN zY|nybY8hV>Um{Qpdk84w<6R-&K+&A#Rf^pEDtzX;5WDTim1OA)`%4s>7PAxKw3I~| z-q*r!C^@GwmIQ7>_QTghdL*o_`10n}zI$t;$rT!R3`;-W*fCfi@`{U0hLQ9NNnAWa zCW&$DH3oyYyV0@ZSYZW;dupzHGqWs7%j`7Cvv@yu>waR?YiTr0pJ&!Qx=~bQzP=%9 zTiW#AQ|#)bTYS+;6X+x2vh)t1ZsV4>64t)@ujMyeJih#kz?^(-HfWyz-~aTq4mlH<=6<0~Ql8(;{<9U42?gU^BW97sm6d zvepPhdrh!c#76l(=|ON*bH^LgvNIO-64Tes?9-dwIdLERQtYIj4&_Xd{F^;9{VHzE zqM}Sjbu;UC$(eDc4_rBzxQ|i9EiCDweJ5`{pAg{RL3A01gGIssg;4@G4c&OoJMLqR z%o|{tP?*2wrgt=KB(vr=d? z{>|v^owV!RHX80^`_#qN_9-bT()cdmbIpl9c=zB8=0i=oYyRfmo?LylA)PNrd%taJ z5#brFk$T@*TDK&V*Y4`Z)ID|y^<K&$JMBn5t$Db&ruc|H+0 z!_B*O&Eq2;>|RR;|AkuC6sp-^E!4^BaY}8Xo?|qwNS<6F+=$#-c=0N$ezg#BQXAkd zqq;eK0>`a9ToDxJ(u(%zN+u>E;a0^<1uZ8GX*@$9tI_TTt7S^ z7+)Q_4Qf0)3hfZ49j_vC&Pqs4GgPHUg7Sx@Y{AOEgSt~O3Hi@L=6T)50N_R=Kl4}e zW#I7@J=ts-a~o6fjk3aaD*zB?`nk}NpbeXrd>71xXTGv=9{&R~j#$RGJHX@ug#=Y- z3VF-)j8f}AV(`HtDijtMT=uehF;VGy1TSc1xHRp`e7|`Myq`cdcQNYQ-As#R5tHmlRQVmP)+@jHYjZgfzZ|7f~z6DlOQ>oO|hO3RWBdZ%a|JZt* Lfw?!hh2HoL&lvNy diff --git a/res/locales/helpOnTheFly.csv b/res/locales/helpOnTheFly.csv index fdf9dcae4..786a079b8 100644 --- a/res/locales/helpOnTheFly.csv +++ b/res/locales/helpOnTheFly.csv @@ -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_TEXT_1";;"Type “help slow” for the ways to make the game run faster.";;;;;;;;;;;;;;;;;;;"게임이 느리게 돌아간다면 “help slow”를 입력해 보세요." -"HELP_OTF_MAIN_TEXT_2";;"Press PageUp/PageDown to scroll the messages.";;;;;;;;;;;;;;;;;;;"PageUp/PageDown 키를 사용해 메시지를 스크롤할 수 있습니다." -"HELP_OTF_MAIN_TEXT_3";;"Utility keys:";;;;;;;;;;;;;;;;;;;"기능 키:" -"HELP_OTF_MAIN_TEXT_4";;"• F3: basic information";;;;;;;;;;;;;;;;;;;"• F3: 기본 정보" -"HELP_OTF_MAIN_TEXT_5";;"• F7: (debug only) toggle light blending";;;;;;;;;;;;;;;;;;;"• F7: (디버그용) 광원 블렌딩 켜고 끄기" -"HELP_OTF_MAIN_TEXT_6";;"• F8: toggle smooth lighting";;;;;;;;;;;;;;;;;;;"• F8: 부드러운 광원 켜고 끄기" +"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_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_TEXT_1";;"To make your game run faster:";;;;;;;;;;;;;;;;;;;"게임을 빠르게 하려면" -"HELP_OTF_SLOW_TEXT_2";;"• Reset screen zoom to 1.";;;;;;;;;;;;;;;;;;;"• 화면 줌을 1로 돌려주세요. " -"HELP_OTF_SLOW_TEXT_3";;"• Turn off basic information window using F3.";;;;;;;;;;;;;;;;;;;"• F3을 눌러 기본 정보 창을 꺼 주세요." -"HELP_OTF_SLOW_TEXT_4";;"• Turn off smooth lighting. You can do it now by pressing F8.";;;;;;;;;;;;;;;;;;;"• 부드러운 광원 효과를 꺼 주세요. 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 d‘informations.";;;;;;;;;;;;;;;;;;"• 기본 정보 창을 꺼 주세요." +"HELP_OTF_SLOW_1";;"• Turn off smooth lighting. You can do it now by pressing F8.";"• Désactivez éclairage lisse en utilisant F8.";;;;;;;;;;;;;;;;;;"• 부드러운 광원 효과를 꺼 주세요. F8을 사용할 수 있습니다." diff --git a/res/raw/CreatureHuman.json b/res/raw/creatures/CreatureHuman.json similarity index 100% rename from res/raw/CreatureHuman.json rename to res/raw/creatures/CreatureHuman.json diff --git a/res/raw/FactionGenericPlayer.json b/res/raw/factions/FactionGenericPlayer.json similarity index 100% rename from res/raw/FactionGenericPlayer.json rename to res/raw/factions/FactionGenericPlayer.json diff --git a/res/raw/FactionSigrid.json b/res/raw/factions/FactionSigrid.json similarity index 100% rename from res/raw/FactionSigrid.json rename to res/raw/factions/FactionSigrid.json diff --git a/res/raw/FactionWildHamletTemplate.json b/res/raw/factions/FactionWildHamletTemplate.json similarity index 100% rename from res/raw/FactionWildHamletTemplate.json rename to res/raw/factions/FactionWildHamletTemplate.json diff --git a/src/com/Torvald/Terrarum/ABOUT b/src/com/Torvald/Terrarum/ABOUT deleted file mode 100644 index 5b11390bc..000000000 --- a/src/com/Torvald/Terrarum/ABOUT +++ /dev/null @@ -1,130 +0,0 @@ - -== CHALLENGING, NOT PUNISHING == https://www.youtube.com/watch?v=ea6UuRTjkKs - - 1. CONSISTENT RULES - - No arbitrary unstoppable death - - 2. Player's skill involved - - Can play around, not restart - - 3. Usability of in-game tools - - Players should be able to 'regret' their strategy and adjust. - - 4. Comfortable control - - 5. Make players overcome the challenge, not defeating them - - 6. Let players have "aha" moment when they failed. - - Make them hungry to retry with new strategies. - - Some small things they've could done differently - - e.g. "One-big-hit didn't worked, may I should've picked up high DPS one" - - -== MORE DEPTH, LESS COMPLEXITY == https://www.youtube.com/watch?v=jVL4st0blGU - - 1. Memorise less! - - Less burden to, even starting the game - - Start with gentle learning curve, getting slowly steep - - Intuitive UX (UI, control, ...) - - Good tutorial = lessens complexity - - 2. Intuitive! - - 3. Calculations per second - - reduce! - - 4. Players have to know everything to even begin the play == FAIL (irreducible complexity) - - Make them get familiar with rules of the game - - Dwarf Fortress failed this! - - -== Lots of things players can play with (aka don't make them bored) == - - - Combat, battle, building, mechanics, adventure, dungeon explore, spelunking - - Not scaled; easy combat, tough combat, tedious combat, etc. - - -== Achieving perfect imbalance == https://www.youtube.com/watch?v=e31OSVZF77w - - - Make sure no matter how you skilled, your playable character cannot be good at everything - - Give players __wide pool of options__ to solve problem - (kill the boss, defend their adobe, fast transportation, etc.) - - --=*## What feeling do you want to convey? ##*=- - - -== Always think WHY you want to add _something_ on the game == - - - e.g. Why are you adding RPG leveling system? What it would do to the players? How would they play with? - - - -See also: HEARTS, CLUBS, DIAMONDS, SPADES: PLAYERS WHO SUIT MUDS - - -==================================== - - -== Friendlier version of Dwarf Fortress Adventure mode == - - - Yet _lots of fun_ - - Add Fortress mode features by 'make your own settling' - - Hard to actually die, but once you die, you're done. - + Config: imtooyoungtodie for easy mode - - - Genre: Adventure, Open world (towns in RPG, building, town managing (conquer existing one or - you build one and persuade existing people to move in) -> See Dwarf Fortress and Animal Crossing) - - * Adventure: adventure this vast—5,5 km wide—world, discover new (and good/horrible) things - - * Open world: - - Building: building your own houses, structures, etc. - - Town managing: - 1. Build your own little hamlet and manage it - or- - 2. Conquer existing one and become a ruler - The town is a special hamlet that can be tailored for your taste - - Survival: - mobs will trying to attack your assets (yourself, your hamlet, your people) - - - -== Side view == - -== Interact menu w/ mouse right == - -== Pixelated sprites == - - Use 2x sprites if rotating does not work well - - -== User experience == - - * Indicative mouse cursor - - -== Game mechanics == - - * 24 pixels == 1 metre - - -== Purpose of the game == - - * Boss - - Will be mentioned/shown as absolute _evil_. - - But actually is not. - - * Theme - - Is an evil really really is what we think? - - Is there a thing as 'absolute evil'? - - * Boss character - - From debugger character - - Name key: "Sigriðr hinn Dróttningin" (can be changed) - * Little setting - - A ruler, hated by people - - * Mechanics - - Beating boss does not ends the game, but grants an ability to - create new character as it. - \ No newline at end of file diff --git a/src/com/Torvald/Terrarum/COPYING b/src/com/Torvald/Terrarum/COPYING deleted file mode 100644 index e78cbe395..000000000 --- a/src/com/Torvald/Terrarum/COPYING +++ /dev/null @@ -1,6 +0,0 @@ -* Terrarum by Torvald - Copyright 2015-2016 Torvald. All rights reserved. - mailto: alswo9628 *at* !gmail! *dot* !com! - -* Simplex Noise Generator, version 2012-03-09 by Stefan Gustavson - Released as public domain diff --git a/src/com/Torvald/Terrarum/Game.kt b/src/com/Torvald/Terrarum/Game.kt index bd94b8966..78c925202 100644 --- a/src/com/Torvald/Terrarum/Game.kt +++ b/src/com/Torvald/Terrarum/Game.kt @@ -14,13 +14,11 @@ import com.torvald.terrarum.mapdrawer.MapDrawer import com.torvald.terrarum.mapgenerator.MapGenerator import com.torvald.terrarum.mapgenerator.RoguelikeRandomiser import com.torvald.terrarum.tileproperties.TilePropCodex -import com.torvald.terrarum.tilestats.TileStat +import com.torvald.terrarum.tilestats.TileStats import com.torvald.terrarum.ui.BasicDebugInfoWindow import com.torvald.terrarum.ui.ConsoleWindow import com.torvald.terrarum.ui.Notification import com.torvald.terrarum.ui.UIHandler -import com.jme3.math.FastMath -import org.lwjgl.opengl.ARBShaderObjects import org.lwjgl.opengl.GL11 import org.newdawn.slick.* import org.newdawn.slick.fills.GradientFill @@ -69,17 +67,17 @@ constructor() : BasicGameState() { private val ENV_SUNLIGHT_DELTA = MapDrawer.ENV_COLTEMP_NOON - ENV_COLTEMP_SUNRISE - var memInUse: Long = 0 + val memInUse: Long get() = ManagementFactory.getMemoryMXBean().heapMemoryUsage.used shr 20 - var totalVMMem: Long = 0 + val totalVMMem: Long get() = Runtime.getRuntime().maxMemory() shr 20 - var auth = Authenticator() + val auth = Authenticator() private var update_delta: Int = 0 - private val KEY_LIGHTMAP_RENDER = Key.F7 - private val KEY_LIGHTMAP_SMOOTH = Key.F8 + val KEY_LIGHTMAP_RENDER = Key.F7 + val KEY_LIGHTMAP_SMOOTH = Key.F8 @Throws(SlickException::class) override fun init(gameContainer: GameContainer, stateBasedGame: StateBasedGame) { @@ -109,8 +107,8 @@ constructor() : BasicGameState() { // add new player and put it to actorContainer - //player = PFSigrid.build() - player = PFCynthia.create() + player = PFSigrid.create() + //player = PFCynthia.create() //player.setNoClip(true); actorContainer.add(player) @@ -141,7 +139,7 @@ constructor() : BasicGameState() { GameController.processInput(gc.input) - TileStat.update() + TileStats.update() MapDrawer.update(gc, delta) MapCamera.update(gc, delta) @@ -189,8 +187,10 @@ constructor() : BasicGameState() { MapCamera.renderBehind(gc, g) - actorContainer.forEach { actor -> if (actor is Visible) actor.drawBody(gc, g) } - actorContainer.forEach { actor -> if (actor is Glowing) actor.drawGlow(gc, g) } + actorContainer.forEach { actor -> + if (actor is Visible) actor.drawBody(gc, g) + if (actor is Glowing) actor.drawGlow(gc, g) + } player.drawBody(gc, g) player.drawGlow(gc, g) diff --git a/src/com/Torvald/Terrarum/GameMap/GameMap.kt b/src/com/Torvald/Terrarum/GameMap/GameMap.kt index 53bfc8a05..3325c6101 100644 --- a/src/com/Torvald/Terrarum/GameMap/GameMap.kt +++ b/src/com/Torvald/Terrarum/GameMap/GameMap.kt @@ -1,11 +1,3 @@ -/* - * MapLoader version 1.2 - * Release date 2013-05-20 - * Copyright 2013 SKYHi14 - * - * The program is distributed in GNU GPL Licence version 3. - * See http://www.gnu.org/licenses/gpl.html for information. - */ package com.torvald.terrarum.gamemap @@ -89,23 +81,33 @@ constructor(//properties val damageDataArray: Array get() = terrainDamage.dataPair - fun getTileFromWall(x: Int, y: Int): Int { - return layerWall.getTile(x, y) * PairedMapLayer.RANGE + getWallDamage(x, y) + fun getTileFromWall(x: Int, y: Int): Int? { + val wall: Int? = layerWall.getTile(x, y) + val wallDamage: Int? = getWallDamage(x, y) + return if (wall == null || wallDamage == null) + null + else + wall * PairedMapLayer.RANGE + wallDamage } - fun getTileFromTerrain(x: Int, y: Int): Int { - return layerTerrain.getTile(x, y) * PairedMapLayer.RANGE + getTerrainDamage(x, y) + fun getTileFromTerrain(x: Int, y: Int): Int? { + val terrain: Int? = layerTerrain.getTile(x, y) + val terrainDamage: Int? = getTerrainDamage(x, y) + return if (terrain == null || terrainDamage == null) + null + else + terrain * PairedMapLayer.RANGE + terrainDamage } - fun getTileFromWire(x: Int, y: Int): Int { + fun getTileFromWire(x: Int, y: Int): Int? { return layerWire.getTile(x, y) } - fun getWallDamage(x: Int, y: Int): Int { + fun getWallDamage(x: Int, y: Int): Int? { return wallDamage.getData(x, y) } - fun getTerrainDamage(x: Int, y: Int): Int { + fun getTerrainDamage(x: Int, y: Int): Int? { return terrainDamage.getData(x, y) } @@ -147,7 +149,7 @@ constructor(//properties layerWire.data[y][x] = tile } - fun getTileFrom(mode: Int, x: Int, y: Int): Int { + fun getTileFrom(mode: Int, x: Int, y: Int): Int? { if (mode == TERRAIN) { return getTileFromTerrain(x, y) } diff --git a/src/com/Torvald/Terrarum/GameMap/MapLayer.kt b/src/com/Torvald/Terrarum/GameMap/MapLayer.kt index cb4384efd..1c992af4b 100644 --- a/src/com/Torvald/Terrarum/GameMap/MapLayer.kt +++ b/src/com/Torvald/Terrarum/GameMap/MapLayer.kt @@ -1,9 +1,5 @@ package com.torvald.terrarum.gamemap -import java.io.Serializable -import java.util.Spliterator -import java.util.function.Consumer - /** * Created by minjaesong on 16-01-17. */ @@ -40,8 +36,11 @@ class MapLayer(var width: Int, var height: Int) : Iterable { } } - internal fun getTile(x: Int, y: Int): Int { - return uint8ToInt32(data[y][x]) + internal fun getTile(x: Int, y: Int): Int? { + return if (x !in 0..width - 1 || y !in 0..height - 1) + null + else + uint8ToInt32(data[y][x]) } internal fun setTile(x: Int, y: Int, tile: Byte) { @@ -51,8 +50,7 @@ class MapLayer(var width: Int, var height: Int) : Iterable { private fun uint8ToInt32(x: Byte): Int = java.lang.Byte.toUnsignedInt(x) companion object { - - @Transient @JvmStatic val RANGE = 256 + @Transient val RANGE = 256 } } diff --git a/src/com/Torvald/Terrarum/GameMap/PairedMapLayer.kt b/src/com/Torvald/Terrarum/GameMap/PairedMapLayer.kt index 44e7d7f60..f62c1d5fc 100644 --- a/src/com/Torvald/Terrarum/GameMap/PairedMapLayer.kt +++ b/src/com/Torvald/Terrarum/GameMap/PairedMapLayer.kt @@ -53,13 +53,17 @@ class PairedMapLayer(width: Int, var height: Int) : Iterable { } } - internal fun getData(x: Int, y: Int): Int { - if (x and 0x1 == 0) - // higher four bits for i = 0, 2, 4, ... - return (java.lang.Byte.toUnsignedInt(dataPair[y][x / 2]) and 0xF0) ushr 4 - else - // lower four bits for i = 1, 3, 5, ... - return java.lang.Byte.toUnsignedInt(dataPair[y][x / 2]) and 0x0F + internal fun getData(x: Int, y: Int): Int? { + return if (x !in 0..width * 2 - 1 || y !in 0..height - 1) + null + else { + if (x and 0x1 == 0) + // higher four bits for i = 0, 2, 4, ... + (java.lang.Byte.toUnsignedInt(dataPair[y][x / 2]) and 0xF0) ushr 4 + else + // lower four bits for i = 1, 3, 5, ... + java.lang.Byte.toUnsignedInt(dataPair[y][x / 2]) and 0x0F + } } internal fun setData(x: Int, y: Int, data: Int) { diff --git a/src/com/Torvald/Terrarum/GameMap/WorldTime.kt b/src/com/Torvald/Terrarum/GameMap/WorldTime.kt index d7f263e5a..5a275722b 100644 --- a/src/com/Torvald/Terrarum/GameMap/WorldTime.kt +++ b/src/com/Torvald/Terrarum/GameMap/WorldTime.kt @@ -143,11 +143,11 @@ class WorldTime { /** * 22h */ - @Transient val DAY_LENGTH = 79200 //must be the multiple of 3600 + val DAY_LENGTH = 79200 //must be the multiple of 3600 - @Transient val HOUR_SEC: Int = 3600 - @Transient val MINUTE_SEC: Int = 60 - @Transient val HOUR_MIN: Int = 60 - @Transient val GAME_MIN_TO_REAL_SEC: Float = 60f + val HOUR_SEC: Int = 3600 + val MINUTE_SEC: Int = 60 + val HOUR_MIN: Int = 60 + val GAME_MIN_TO_REAL_SEC: Float = 60f } } \ No newline at end of file diff --git a/src/com/Torvald/Terrarum/LangPack/Lang.kt b/src/com/Torvald/Terrarum/LangPack/Lang.kt index a8ad22b8b..89ec8ae2f 100644 --- a/src/com/Torvald/Terrarum/LangPack/Lang.kt +++ b/src/com/Torvald/Terrarum/LangPack/Lang.kt @@ -39,9 +39,6 @@ object Lang { init { lang = HashMap() - // read polyglot.csv first and use this list as a pivot - var langPackCSV: List = CSVFetcher.readCSV(PATH_TO_CSV + CSV_MAIN) - // append CSV records to the main langpack val file = File(PATH_TO_CSV) val filter = FilenameFilter { dir, name -> name.contains(".csv") && !name.contains(NAMESET_PREFIX) } @@ -51,15 +48,11 @@ object Lang { csv.forEach { it -> lang.put(it.get(CSV_COLUMN_FIRST), it) } } - // lang.put(record.get(CSV_COLUMN_FIRST), record) - - // Fill lang table - // langPackCSV.forEach({ this.appendToLangByStringID(it) }) - - + // sort word lists Arrays.sort(ENGLISH_WORD_NORMAL_PLURAL) Arrays.sort(FRENCH_WORD_NORMAL_PLURAL) + // reload correct (C/J) unihan fonts if applicable try { (Terrarum.gameFontWhite as GameFontWhite).reloadUnihan() } diff --git a/src/com/Torvald/Terrarum/MECHNANICS b/src/com/Torvald/Terrarum/MECHNANICS deleted file mode 100644 index 779518490..000000000 --- a/src/com/Torvald/Terrarum/MECHNANICS +++ /dev/null @@ -1,112 +0,0 @@ - -== Weapon tier == - - Natural / Common Stone -> Copper -> Iron -> Silver -> Titanium - Forging --------------> Steel --------^ - Exotic ('elven') Glass Aurichalcum - Special (something 'adamant') ??? (Use material spec of CNT, tensile strength 180 GPa) - - = Metal graphics - - Gold: Hue 43, low Saturation - - Aurichalcum: Hue 43, mid-high Saturation - - Copper: Hue 33, - - Copper rust: Hue 160 - - Iron rust: Hue 21 - - -== Size variation == - - Race base weapon/tool size <- 10 [kg] - Size tolerance <- (50% * str/1000), or say, 20% - - If the size is bigger than tolerable, weapon speed severely slows down, tools become unusable - if use time >= 0.75 second, the weapon/tool cannot be equipped. - Small weapons/tools gains no (dis)advantage - - When drawing: scale by (craftedWeaponSize / baseWeaponSize) - - Crafted tool/weapon size is dependent to the baseRaceMass. - - -== Gemstone tier == - - Topaz -> R·G·B -> Diamond·Amethyst - - -== Colouring == - - Natural: Use 4096 - Magical/Surreal: Use 24 Bits - - = Colouring of potion - - Randomised, roguelike fashion - - Choose Col(R40, G40, B40) from set of finite cards: - 39, 39, 19, 19, 0, 0 - - MULTIPLY blend chosen colour with white texture - - -== Roguelike identity == - - = Randomised things - - E.g. potion - Lime-coloured potion - First play: "Potion (???)" - After drank: "Potion (Healing)" is revealed. - - Second (new) play: "Potion (???)" - After drank: "Potion (Neurotoxin)" is revealed. - - -== Making sprite == - - * Layers - - (Optional) Glow - - (Optional) Hair foreground - - Right arm dress - - Right arm body - - Dress - - Boots - - Body - - (Optional) Hair accessory - - Hair - - Head - - Left arm dress - - Left arm body - - (Optional) SFX - - * Size - - Regular sprite 'height' (hitbox height) : 40 px - - Apparent height may vary - - -== Chargen == - - * Select hair, colours, then compile them into single spritesheet - - * NO gender distinction, but have masculine/neutral/feminine looks (in clothing, hairstyles, etc.) - - * Colour: 4096 colours (12-bit 0x000 - 0xFFF) - - * 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) - - -== (De)serialisation == - - see SAVE_FORMAT - - -== Actor being universal == - - * Utility tiles that have states (e.g. noteblock) are implemented using Actor. diff --git a/src/com/Torvald/Terrarum/MapDrawer/LightmapRenderer.kt b/src/com/Torvald/Terrarum/MapDrawer/LightmapRenderer.kt index 07f611c14..0f51eb391 100644 --- a/src/com/Torvald/Terrarum/MapDrawer/LightmapRenderer.kt +++ b/src/com/Torvald/Terrarum/MapDrawer/LightmapRenderer.kt @@ -19,7 +19,7 @@ object LightmapRenderer { * 8-Bit RGB values */ @Volatile private var lightMapMSB: Array? = null - @Volatile private var lightMapLSB: Array? = null + @Volatile private var lightMapLSB: Array? = null // modify this to CharArray to implement 30-bit RGB private var lightMapInitialised = false /** @@ -38,14 +38,14 @@ object LightmapRenderer { private val TSIZE = MapDrawer.TILE_SIZE // color model related vars - const val MUL = 256 - const val MUL_2 = 256 * 256 - const val CHANNEL_MAX = 255 - const val CHANNEL_MAX_FLOAT = 255f - const val COLOUR_DOMAIN_SIZE = 256 * 256 * 256 + const val MUL = 256 // modify this to 1024 to implement 30-bit RGB + const val MUL_2 = MUL * MUL + const val CHANNEL_MAX = MUL - 1 + const val CHANNEL_MAX_FLOAT = CHANNEL_MAX.toFloat() + const val COLOUR_DOMAIN_SIZE = MUL * MUL_2 - private const val deprecatedFeatureDebatable = "This feature is debatable. Do not use it yet." + private const val deprecatedFeatureDebatable = "The usage of this feature is debatable. Do not use it yet." @Deprecated(deprecatedFeatureDebatable) fun addLantern(x: Int, y: Int, intensity: Int) { @@ -75,8 +75,12 @@ object LightmapRenderer { } } - fun getLight(x: Int, y: Int): Int = - java.lang.Byte.toUnsignedInt(lightMapLSB!![y][x]) or (lightMapMSB!![y][x].toInt() shl 8) + fun getLight(x: Int, y: Int): Int? = + if (x !in 0..Terrarum.game.map.width - 1 || y !in 0..Terrarum.game.map.height - 1) + null + else + java.lang.Byte.toUnsignedInt(lightMapLSB!![y][x]) or (lightMapMSB!![y][x].toInt() shl 8) + fun setLight(x: Int, y: Int, colour: Int) { lightMapLSB!![y][x] = (colour and 0xFF).toByte() @@ -164,7 +168,7 @@ object LightmapRenderer { while (x < for_x_end) { // smooth if (Terrarum.game.screenZoom >= 1 && Terrarum.gameConfig.getAsBoolean("smoothlighting") ?: false) { - val thisLightLevel = getLight(x, y) + val thisLightLevel = getLight(x, y) ?: 0 if (y > 0 && x < for_x_end && thisLightLevel == 0 && getLight(x, y - 1) == 0) { try { @@ -204,32 +208,32 @@ object LightmapRenderer { thisLightLevel else maximiseRGB( - getLight(x, y), - getLight(x, y - 1)) + getLight(x, y) ?: 0, + getLight(x, y - 1) ?: 0) val d = if (y == 0) thisLightLevel else if (y == Terrarum.game.map.height - 1) thisLightLevel else maximiseRGB( - getLight(x, y), - getLight(x, y + 1)) + getLight(x, y) ?: 0, + getLight(x, y + 1) ?: 0) val b = if (x == 0) thisLightLevel else if (x == Terrarum.game.map.width - 1) thisLightLevel else maximiseRGB( - getLight(x, y), - getLight(x - 1, y)) + getLight(x, y) ?: 0, + getLight(x - 1, y) ?: 0) val c = if (x == 0) thisLightLevel else if (x == Terrarum.game.map.width - 1) thisLightLevel else maximiseRGB( - getLight(x, y), - getLight(x + 1, y)) + getLight(x, y) ?: 0, + getLight(x + 1, y) ?: 0) val colourMapItoL = IntArray(4) colourMapItoL[0] = colourLinearMix(a, b) colourMapItoL[1] = colourLinearMix(a, c) @@ -260,7 +264,7 @@ object LightmapRenderer { if (x + sameLevelCounter >= for_x_end) break } - g.color = Color(getLight(x, y)) + g.color = Color(getLight(x, y) ?: 0) g.fillRect( Math.round(x.toFloat() * TSIZE.toFloat() * Terrarum.game.screenZoom).toFloat(), Math.round(y.toFloat() * TSIZE.toFloat() * Terrarum.game.screenZoom).toFloat(), (FastMath.ceil( TSIZE * Terrarum.game.screenZoom) * sameLevelCounter).toFloat(), FastMath.ceil(TSIZE * Terrarum.game.screenZoom).toFloat()) @@ -347,13 +351,13 @@ object LightmapRenderer { if (xoff != yoff && -xoff != yoff) { // 'v' tiles if (!outOfMapBounds(x + xoff, y + yoff)) { - nearby = getLight(x + xoff, y + yoff) + nearby = getLight(x + xoff, y + yoff) ?: 0 } } else if (xoff != 0 && yoff != 0) { // 'a' tiles if (!outOfMapBounds(x + xoff, y + yoff)) { - nearby = darkenUniformInt(getLight(x + xoff, y + yoff), 12) //2 for 40step + nearby = darkenUniformInt(getLight(x + xoff, y + yoff) ?: 0, 12) //2 for 40step // mix some to have more 'spreading' // so that light spreads in a shape of an octagon instead of a diamond } @@ -631,7 +635,7 @@ object LightmapRenderer { private fun clampFloat(i: Float): Float = if (i < 0) 0f else if (i > 1) 1f else i - fun getValueFromMap(x: Int, y: Int): Int = getLight(x, y) + fun getValueFromMap(x: Int, y: Int): Int? = getLight(x, y) private fun purgePartOfLightmap(x1: Int, y1: Int, x2: Int, y2: Int) { try { diff --git a/src/com/Torvald/Terrarum/MapDrawer/MapCamera.kt b/src/com/Torvald/Terrarum/MapDrawer/MapCamera.kt index 00f38d179..d846cc82f 100644 --- a/src/com/Torvald/Terrarum/MapDrawer/MapCamera.kt +++ b/src/com/Torvald/Terrarum/MapDrawer/MapCamera.kt @@ -108,7 +108,7 @@ object MapCamera { , TileNameCode.PLANK_EBONY , TileNameCode.PLANK_NORMAL , TileNameCode.SAND - , TileNameCode.SAND_BEACH + , TileNameCode.SAND_WHITE , TileNameCode.SAND_RED , TileNameCode.SAND_DESERT , TileNameCode.SAND_BLACK @@ -230,7 +230,7 @@ object MapCamera { for (y in for_y_start..for_y_end - 1) { for (x in for_x_start..for_x_end - 1) { - val thisTile: Int + val thisTile: Int? if (mode % 3 == WALL) thisTile = map.getTileFromWall(x, y) else if (mode % 3 == TERRAIN) @@ -248,12 +248,14 @@ object MapCamera { (mode == WALL || mode == TERRAIN) // not an air tile - && thisTile > 0 + && (thisTile ?: 0) > 0 && // check if light level of upper tile is zero and // that of this tile is also zero - (y > 0 && !(LightmapRenderer.getValueFromMap(x, y).toInt() == 0 && LightmapRenderer.getValueFromMap(x, y - 1).toInt() == 0) || // check if light level of this tile is zero, for y = 0 - y == 0 && LightmapRenderer.getValueFromMap(x, y).toInt() > 0)) { + (y > 0 && !(LightmapRenderer.getValueFromMap(x, y) ?: 0.toInt() == 0 + && LightmapRenderer.getValueFromMap(x, y - 1) ?: 0.toInt() == 0) + // check if light level of this tile is zero, for y = 0 + || y == 0 && LightmapRenderer.getValueFromMap(x, y) ?: 0.toInt() > 0)) { val nearbyTilesInfo: Int if (isWallSticker(thisTile)) { @@ -269,11 +271,11 @@ object MapCamera { val thisTileX: Int if (!noDamageLayer) - thisTileX = PairedMapLayer.RANGE * (thisTile % PairedMapLayer.RANGE) + nearbyTilesInfo + thisTileX = PairedMapLayer.RANGE * ((thisTile ?: 0) % PairedMapLayer.RANGE) + nearbyTilesInfo else thisTileX = nearbyTilesInfo - val thisTileY = thisTile / PairedMapLayer.RANGE + val thisTileY = (thisTile ?: 0) / PairedMapLayer.RANGE if (drawModeTilesBlendMul) { if (isBlendMul(thisTile)) { @@ -311,31 +313,12 @@ object MapCamera { * * * @return [0-15] 1: up, 2: right, 4: down, 8: left */ - private fun getNearbyTilesInfo(x: Int, y: Int, mode: Int, mark: Int): Int { + private fun getNearbyTilesInfo(x: Int, y: Int, mode: Int, mark: Int?): Int { val nearbyTiles = IntArray(4) - if (x == 0) { - nearbyTiles[NEARBY_TILE_KEY_LEFT] = 4096 - } else { - nearbyTiles[NEARBY_TILE_KEY_LEFT] = map.getTileFrom(mode, x - 1, y) - } - - if (x == map.width - 1) { - nearbyTiles[NEARBY_TILE_KEY_RIGHT] = 4096 - } else { - nearbyTiles[NEARBY_TILE_KEY_RIGHT] = map.getTileFrom(mode, x + 1, y) - } - - if (y == 0) { - nearbyTiles[NEARBY_TILE_KEY_UP] = 0 - } else { - nearbyTiles[NEARBY_TILE_KEY_UP] = map.getTileFrom(mode, x, y - 1) - } - - if (y == map.height - 1) { - nearbyTiles[NEARBY_TILE_KEY_DOWN] = 4096 - } else { - nearbyTiles[NEARBY_TILE_KEY_DOWN] = map.getTileFrom(mode, x, y + 1) - } + nearbyTiles[NEARBY_TILE_KEY_LEFT] = map.getTileFrom(mode, x - 1, y) ?: 4096 + nearbyTiles[NEARBY_TILE_KEY_RIGHT] = map.getTileFrom(mode, x + 1, y) ?: 4096 + nearbyTiles[NEARBY_TILE_KEY_UP] = map.getTileFrom(mode, x, y - 1) ?: 4906 + nearbyTiles[NEARBY_TILE_KEY_DOWN] = map.getTileFrom(mode, x, y + 1) ?: 4096 // try for var ret = 0 @@ -350,29 +333,10 @@ object MapCamera { private fun getNearbyTilesInfoNonSolid(x: Int, y: Int, mode: Int): Int { val nearbyTiles = IntArray(4) - if (x == 0) { - nearbyTiles[NEARBY_TILE_KEY_LEFT] = 4096 - } else { - nearbyTiles[NEARBY_TILE_KEY_LEFT] = map.getTileFrom(mode, x - 1, y) - } - - if (x == map.width - 1) { - nearbyTiles[NEARBY_TILE_KEY_RIGHT] = 4096 - } else { - nearbyTiles[NEARBY_TILE_KEY_RIGHT] = map.getTileFrom(mode, x + 1, y) - } - - if (y == 0) { - nearbyTiles[NEARBY_TILE_KEY_UP] = 0 - } else { - nearbyTiles[NEARBY_TILE_KEY_UP] = map.getTileFrom(mode, x, y - 1) - } - - if (y == map.height - 1) { - nearbyTiles[NEARBY_TILE_KEY_DOWN] = 4096 - } else { - nearbyTiles[NEARBY_TILE_KEY_DOWN] = map.getTileFrom(mode, x, y + 1) - } + nearbyTiles[NEARBY_TILE_KEY_LEFT] = map.getTileFrom(mode, x - 1, y) ?: 4096 + nearbyTiles[NEARBY_TILE_KEY_RIGHT] = map.getTileFrom(mode, x + 1, y) ?: 4096 + nearbyTiles[NEARBY_TILE_KEY_UP] = map.getTileFrom(mode, x, y - 1) ?: 4096 + nearbyTiles[NEARBY_TILE_KEY_DOWN] = map.getTileFrom(mode, x, y + 1) ?: 4096 // try for var ret = 0 @@ -392,25 +356,10 @@ object MapCamera { private fun getNearbyTilesInfoWallSticker(x: Int, y: Int): Int { val nearbyTiles = IntArray(4) val NEARBY_TILE_KEY_BACK = NEARBY_TILE_KEY_UP - if (x == 0) { - nearbyTiles[NEARBY_TILE_KEY_LEFT] = 4096 - } else { - nearbyTiles[NEARBY_TILE_KEY_LEFT] = map.getTileFrom(TERRAIN, x - 1, y) - } - - if (x == map.width - 1) { - nearbyTiles[NEARBY_TILE_KEY_RIGHT] = 4096 - } else { - nearbyTiles[NEARBY_TILE_KEY_RIGHT] = map.getTileFrom(TERRAIN, x + 1, y) - } - - if (y == map.height - 1) { - nearbyTiles[NEARBY_TILE_KEY_DOWN] = 4096 - } else { - nearbyTiles[NEARBY_TILE_KEY_DOWN] = map.getTileFrom(TERRAIN, x, y + 1) - } - - nearbyTiles[NEARBY_TILE_KEY_BACK] = map.getTileFrom(WALL, x, y) + nearbyTiles[NEARBY_TILE_KEY_LEFT] = map.getTileFrom(TERRAIN, x - 1, y) ?: 4096 + nearbyTiles[NEARBY_TILE_KEY_RIGHT] = map.getTileFrom(TERRAIN, x + 1, y) ?: 4096 + nearbyTiles[NEARBY_TILE_KEY_DOWN] = map.getTileFrom(TERRAIN, x, y + 1) ?: 4096 + nearbyTiles[NEARBY_TILE_KEY_BACK] = map.getTileFrom(WALL, x, y) ?: 4096 try { if (TilePropCodex.getProp(nearbyTiles[NEARBY_TILE_KEY_RIGHT]).isSolid && TilePropCodex.getProp(nearbyTiles[NEARBY_TILE_KEY_LEFT]).isSolid) { @@ -499,12 +448,12 @@ object MapCamera { fun getRenderEndX(): Int = clampWTile(getRenderStartX() + div16(renderWidth) + 2) fun getRenderEndY(): Int = clampHTile(getRenderStartY() + div16(renderHeight) + 2) - private fun isConnectSelf(b: Int): Boolean = TILES_CONNECT_SELF.contains(b) - private fun isConnectMutual(b: Int): Boolean = TILES_CONNECT_MUTUAL.contains(b) - private fun isWallSticker(b: Int): Boolean = TILES_WALL_STICKER.contains(b) - private fun isPlatform(b: Int): Boolean = TILES_WALL_STICKER_CONNECT_SELF.contains(b) + private fun isConnectSelf(b: Int?): Boolean = TILES_CONNECT_SELF.contains(b) + private fun isConnectMutual(b: Int?): Boolean = TILES_CONNECT_MUTUAL.contains(b) + private fun isWallSticker(b: Int?): Boolean = TILES_WALL_STICKER.contains(b) + private fun isPlatform(b: Int?): Boolean = TILES_WALL_STICKER_CONNECT_SELF.contains(b) - private fun isBlendMul(b: Int): Boolean = TILES_BLEND_MUL.contains(b) + private fun isBlendMul(b: Int?): Boolean = TILES_BLEND_MUL.contains(b) private fun setBlendModeMul() { GL11.glEnable(GL11.GL_BLEND) diff --git a/src/com/Torvald/Terrarum/MapDrawer/MapDrawer.kt b/src/com/Torvald/Terrarum/MapDrawer/MapDrawer.kt index 7d2fb9ae1..950642278 100644 --- a/src/com/Torvald/Terrarum/MapDrawer/MapDrawer.kt +++ b/src/com/Torvald/Terrarum/MapDrawer/MapDrawer.kt @@ -3,7 +3,7 @@ package com.torvald.terrarum.mapdrawer import com.torvald.terrarum.gamemap.GameMap import com.torvald.terrarum.Terrarum import com.torvald.terrarum.tileproperties.TileNameCode -import com.torvald.terrarum.tilestats.TileStat +import com.torvald.terrarum.tilestats.TileStats import com.jme3.math.FastMath import org.newdawn.slick.* @@ -44,8 +44,8 @@ object MapDrawer { fun drawEnvOverlay(g: Graphics) { val onscreen_tiles_max = FastMath.ceil(Terrarum.HEIGHT * Terrarum.WIDTH / FastMath.sqr(TILE_SIZE.toFloat())) * 2 val onscreen_tiles_cap = onscreen_tiles_max / 4f - val onscreen_cold_tiles = TileStat.getCount(*TILES_COLD).toFloat() - val onscreen_warm_tiles = TileStat.getCount(*TILES_WARM).toFloat() + val onscreen_cold_tiles = TileStats.getCount(*TILES_COLD).toFloat() + val onscreen_warm_tiles = TileStats.getCount(*TILES_WARM).toFloat() val colTemp_cold = colTempLinearFunc(onscreen_cold_tiles / onscreen_tiles_cap) val colTemp_warm = colTempLinearFunc(-(onscreen_warm_tiles / onscreen_tiles_cap)) diff --git a/src/com/Torvald/Terrarum/MapGenerator/MapGenerator.kt b/src/com/Torvald/Terrarum/MapGenerator/MapGenerator.kt index 3d7c71351..69984f887 100644 --- a/src/com/Torvald/Terrarum/MapGenerator/MapGenerator.kt +++ b/src/com/Torvald/Terrarum/MapGenerator/MapGenerator.kt @@ -2,9 +2,10 @@ package com.torvald.terrarum.mapgenerator import com.torvald.random.HQRNG import com.torvald.terrarum.gamemap.GameMap -import com.torvald.terrarum.gamemap.MapLayer import com.torvald.terrarum.tileproperties.TileNameCode import com.jme3.math.FastMath +import com.sudoplay.joise.Joise +import com.sudoplay.joise.module.* import java.util.* object MapGenerator { @@ -12,13 +13,14 @@ object MapGenerator { private lateinit var map: GameMap private lateinit var random: Random //private static float[] noiseArray; - private var seed: Long = 0 - private var width: Int = 0 - private var height: Int = 0 + private var SEED: Long = 0 + private var WIDTH: Int = 0 + private var HEIGHT: Int = 0 - private lateinit var heightMap: IntArray + //private lateinit var heightMap: IntArray + private lateinit var terrainMap: Array - private var dirtThickness: Int = 0 + private var DIRT_LAYER_DEPTH: Int = 0 private var TERRAIN_AVERAGE_HEIGHT: Int = 0 private var minimumFloatingIsleHeight: Int = 0 @@ -27,7 +29,8 @@ object MapGenerator { private val noiseGrdCaveEnd = 0.54f private val HILL_WIDTH = 256 // power of two! - private val MAX_HILL_HEIGHT = 100 + //private val MAX_HILL_HEIGHT = 100 + private val TERRAIN_UNDULATION = 250 private val CAVE_LARGEST_FEATURE = 200 @@ -35,10 +38,6 @@ object MapGenerator { private var SHORE_WIDTH = 120 private val MAX_OCEAN_DEPTH = 200 - private val TERRAIN_PERTURB_OFFSETMAX = 0 // [-val , val] - private val TERRAIN_PERTURB_LARGESTFEATURE = 256 - private val TERRAIN_PERTURB_RATE = 0.5f - private var GLACIER_MOUNTAIN_WIDTH = 900 private val GLACIER_MOUNTAIN_HEIGHT = 300 @@ -59,54 +58,55 @@ object MapGenerator { private val GRASSCUR_RIGHT = 1 private val GRASSCUR_DOWN = 2 private val GRASSCUR_LEFT = 3 - - @JvmStatic + fun attachMap(map: GameMap) { this.map = map - width = map.width - height = map.height + WIDTH = map.width + HEIGHT = map.height - val widthMulFactor = width / 8192f + val widthMulFactor = WIDTH / 8192f - dirtThickness = (100 * height / 1024f).toInt() - minimumFloatingIsleHeight = (25 * (height / 1024f)).toInt() - TERRAIN_AVERAGE_HEIGHT = height / 4 + DIRT_LAYER_DEPTH = (100 * HEIGHT / 1024f).toInt() + minimumFloatingIsleHeight = (25 * (HEIGHT / 1024f)).toInt() + TERRAIN_AVERAGE_HEIGHT = HEIGHT / 4 OCEAN_WIDTH = Math.round(OCEAN_WIDTH * widthMulFactor) SHORE_WIDTH = Math.round(SHORE_WIDTH * widthMulFactor) GLACIER_MOUNTAIN_WIDTH = Math.round(GLACIER_MOUNTAIN_WIDTH * widthMulFactor) } - @JvmStatic fun setSeed(seed: Long) { - this.seed = seed + this.SEED = seed } /** * Generate terrain and override attached map */ - @JvmStatic fun generateMap() { - random = HQRNG(seed!!) - println("[mapgenerator] Seed: " + seed) + random = HQRNG(SEED) + println("[mapgenerator] Seed: " + SEED) worldOceanPosition = if (random.nextBoolean()) TYPE_OCEAN_LEFT else TYPE_OCEAN_RIGHT - heightMap = raise2(MAX_HILL_HEIGHT / 2) - generateOcean(heightMap) - placeGlacierMount(heightMap) - heightMapToObjectMap(heightMap) + //heightMap = raise2(MAX_HILL_HEIGHT / 2) + //generateOcean(heightMap) + //placeGlacierMount(heightMap) + //heightMapToObjectMap(heightMap) - perturbTerrain() + + terrainMap = raise3() + + + terrainMapToObjectMap() /** - * Todo: more perturbed overworld (harder to supra-navigate) + * 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: Lakes! Aquifers! Lava chambers! * Todo: deserts (variants: SAND_DESERT, SAND_RED) * Todo: volcano(es?) - * Done: variants of beach (SAND_BEACH, SAND_BLACK, SAND_GREEN) + * Done: variants of beach (SAND, SAND_BEACH, SAND_BLACK, SAND_GREEN) */ carveCave( @@ -182,16 +182,16 @@ object MapGenerator { /** TODO Cobaltite, Ilmenite, Aurichalcum (and possibly pitchblende?) */ floodBottomLava() - freeze() - fillOcean() + // freeze() + // fillOcean() plantGrass() //post-process generateFloatingIslands() //wire layer - for (i in 0..height - 1) { - for (j in 0..width - 1) { + for (i in 0..HEIGHT - 1) { + for (j in 0..WIDTH - 1) { map.wireArray[i][j] = 0 } } @@ -211,21 +211,21 @@ object MapGenerator { * @return */ private fun caveGen(xStretch: Float, yStretch: Float): Array { - val noiseMap = Array(height) { FloatArray(width) } + val noiseMap = Array(HEIGHT) { FloatArray(WIDTH) } - val simplexNoise = SimplexNoise(CAVEGEN_LARGEST_FEATURE, CAVEGEN_PERTURB_RATE, seed!!) - val simplexNoisePerturbMap = SimplexNoise(CAVEGEN_LARGEST_FEATURE_PERTURB, 0.5f, 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 xEnd = width * yStretch - val yEnd = height * xStretch + val xEnd = WIDTH * yStretch + val yEnd = HEIGHT * xStretch 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() + 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] @@ -244,8 +244,8 @@ object MapGenerator { // Auto-scaling noise - for (y in 0..height - 1) { - for (x in 0..width - 1) { + for (y in 0..HEIGHT - 1) { + for (x in 0..WIDTH - 1) { val noiseInit = noiseMap[y][x] - lowestNoiseVal val noiseFin = noiseInit * (1f / (highestNoiseVal - lowestNoiseVal)) @@ -264,7 +264,7 @@ object MapGenerator { } private fun generate2DSimplexNoiseWorldSize(xStretch: Float, yStretch: Float): Array { - return generate2DSimplexNoise(width, height, xStretch, yStretch) + return generate2DSimplexNoise(WIDTH, HEIGHT, xStretch, yStretch) } /** @@ -280,7 +280,7 @@ object MapGenerator { * @return matrix in ![x][y]! */ private fun generate2DSimplexNoise(sizeX: Int, sizeY: Int, xStretch: Float, yStretch: Float): Array { - val simplexNoise = SimplexNoise(CAVE_LARGEST_FEATURE, 0.1f, seed!! xor random.nextLong()) + val simplexNoise = SimplexNoise(CAVE_LARGEST_FEATURE, 0.1f, SEED xor random.nextLong()) val xStart = 0f val yStart = 0f @@ -288,8 +288,8 @@ object MapGenerator { /** higher = denser. * Recommended: (width or height) * 3 */ - val xEnd = width * yStretch - val yEnd = height * xStretch + val xEnd = WIDTH * yStretch + val yEnd = HEIGHT * xStretch var lowestNoiseVal = 10000f var highestNoiseVal = -10000f @@ -312,8 +312,8 @@ object MapGenerator { // Auto-scaling noise - for (y in 0..height - 1) { - for (x in 0..width - 1) { + for (y in 0..HEIGHT - 1) { + for (x in 0..WIDTH - 1) { val noiseInit = result[y][x] - lowestNoiseVal val noiseFin = noiseInit * (1f / (highestNoiseVal - lowestNoiseVal)) @@ -364,83 +364,169 @@ object MapGenerator { } /** - * [http://freespace.virgin.net/hugo.elias/models/m_perlin.htm](null) - * @param maxval_div_2 max height (deviation from zero) divided by two. - * * - * @return noise array with range of [-maxval, maxval] + * http://accidentalnoise.sourceforge.net/minecraftworlds.html */ - private fun raise2(maxval_div_2: Int): IntArray { + private fun raise3(): Array { + val noiseMap = Array(HEIGHT, { BitSet(WIDTH) }) - val finalPerlinAmp = maxval_div_2 // 1 + 1/2 + 1/4 + 1/8 + ... == 2 - val perlinOctaves = FastMath.intLog2(maxval_div_2) + 1 - 1 // max: for every 2nd node + // Height = Terrain undulation times 2. + val SCALE_X: Double = (TERRAIN_UNDULATION * 0.5).toDouble() + val SCALE_Y: Double = (TERRAIN_UNDULATION * 0.25).toDouble() - val perlinMap = IntArray(width) // [-2 * finalPerlinAmp, finalPerlinAmp] + val ground_gradient = ModuleGradient() + ground_gradient.setGradient(0.0, 0.0, 0.0, 1.0) - // assert - if (HILL_WIDTH.ushr(perlinOctaves - 1) == 0) { - throw RuntimeException("sample width of zero detected.") - } + /* Lowlands */ - // sample noise and add - for (oct in 1..perlinOctaves) { - // perlinAmp: 16364 -> 8192 -> 4096 -> 2048 -> ... - // This applies persistence of 1/2 - val perlinAmp = finalPerlinAmp.ushr(oct - 1) + val lowland_shape_fractal = ModuleFractal() + lowland_shape_fractal.setType(ModuleFractal.FractalType.FBM) + lowland_shape_fractal.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) + lowland_shape_fractal.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + lowland_shape_fractal.setNumOctaves(4) + lowland_shape_fractal.setFrequency(0.6) + lowland_shape_fractal.seed = SEED xor random.nextLong() + //println(lowland_shape_fractal.seed) - val perlinSampleDist = HILL_WIDTH.ushr(oct - 1) + val lowland_autocorrect = ModuleAutoCorrect() + lowland_autocorrect.setLow(0.0) + lowland_autocorrect.setHigh(1.0) + lowland_autocorrect.setSource(lowland_shape_fractal) - // sample first - val perlinSamples = IntArray(width / perlinSampleDist + 1) - for (sample in perlinSamples.indices) { - perlinSamples[sample] = random.nextInt(perlinAmp * 2) - perlinAmp + val lowland_scale = ModuleScaleOffset() + lowland_scale.setSource(lowland_autocorrect) + lowland_scale.setScale(0.8) + lowland_scale.setOffset(-2.75) + + val lowland_y_scale = ModuleScaleDomain() + lowland_y_scale.setSource(lowland_scale) + lowland_y_scale.setScaleY(0.0) + + val lowland_terrain = ModuleTranslateDomain() + lowland_terrain.setSource(ground_gradient) + lowland_terrain.setAxisYSource(lowland_y_scale) + + /* highlands */ + + val highland_shape_fractal = ModuleFractal() + highland_shape_fractal.setType(ModuleFractal.FractalType.RIDGEMULTI) + highland_shape_fractal.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) + highland_shape_fractal.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + highland_shape_fractal.setNumOctaves(4) + highland_shape_fractal.setFrequency(0.5) // horizontal size. Higher == narrower + highland_shape_fractal.seed = SEED xor random.nextLong() + //println(highland_shape_fractal.seed) + + val highland_autocorrect = ModuleAutoCorrect() + highland_autocorrect.setSource(highland_shape_fractal) + highland_autocorrect.setLow(0.0) + highland_autocorrect.setHigh(1.0) + + val highland_scale = ModuleScaleOffset() + highland_scale.setSource(highland_autocorrect) + highland_scale.setScale(1.4) // vertical size. Higher == taller + highland_scale.setOffset(-2.25) + + val highland_y_scale = ModuleScaleDomain() + highland_y_scale.setSource(highland_scale) + highland_y_scale.setScaleY(0.0) + + val highland_terrain = ModuleTranslateDomain() + highland_terrain.setSource(ground_gradient) + highland_terrain.setAxisYSource(highland_y_scale) + + /* mountains */ + + val mountain_shape_fractal = ModuleFractal() + mountain_shape_fractal.setType(ModuleFractal.FractalType.BILLOW) + mountain_shape_fractal.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) + mountain_shape_fractal.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + mountain_shape_fractal.setNumOctaves(6) + mountain_shape_fractal.setFrequency(0.55) + mountain_shape_fractal.seed = SEED xor random.nextLong() + //println(mountain_shape_fractal.seed) + + val mountain_autocorrect = ModuleAutoCorrect() + mountain_autocorrect.setSource(mountain_shape_fractal) + mountain_autocorrect.setLow(0.0) + mountain_autocorrect.setHigh(1.0) + + val mountain_scale = ModuleScaleOffset() + mountain_scale.setSource(mountain_autocorrect) + mountain_scale.setScale(1.66) + mountain_scale.setOffset(-1.25) + + val mountain_y_scale = ModuleScaleDomain() + mountain_y_scale.setSource(mountain_scale) + mountain_y_scale.setScaleY(0.1) + + val mountain_terrain = ModuleTranslateDomain() + mountain_terrain.setSource(ground_gradient) + mountain_terrain.setAxisYSource(mountain_y_scale) + + /* selection */ + + val terrain_type_fractal = ModuleFractal() + terrain_type_fractal.setType(ModuleFractal.FractalType.MULTI) + terrain_type_fractal.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) + terrain_type_fractal.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + terrain_type_fractal.setNumOctaves(5) + terrain_type_fractal.setFrequency(0.4) // <= 0.33 + terrain_type_fractal.seed = SEED xor random.nextLong() + //println(terrain_type_fractal.seed) + + val terrain_autocorrect = ModuleAutoCorrect() + terrain_autocorrect.setSource(terrain_type_fractal) + terrain_autocorrect.setLow(0.0) + terrain_autocorrect.setHigh(1.0) + + val terrain_type_scale = ModuleScaleDomain() + terrain_type_scale.setScaleY(0.33) + terrain_type_scale.setSource(terrain_autocorrect) + + val terrain_type_cache = ModuleCache() + terrain_type_cache.setSource(terrain_type_scale) + + val highland_mountain_select = ModuleSelect() + highland_mountain_select.setLowSource(highland_terrain) + highland_mountain_select.setHighSource(mountain_terrain) + highland_mountain_select.setControlSource(terrain_type_cache) + highland_mountain_select.setThreshold(0.55) + highland_mountain_select.setFalloff(0.15) + + val highland_lowland_select = ModuleSelect() + highland_lowland_select.setLowSource(lowland_terrain) + highland_lowland_select.setHighSource(highland_mountain_select) + highland_lowland_select.setControlSource(terrain_type_cache) + highland_lowland_select.setThreshold(0.25) + highland_lowland_select.setFalloff(0.15) + + + val ground_select = ModuleSelect() + ground_select.setLowSource(0.0) + ground_select.setHighSource(1.0) + ground_select.setThreshold(0.5) + ground_select.setControlSource(highland_lowland_select) + + val joise = Joise(ground_select) + // fill the area as Joise map + for (y in 0..(TERRAIN_UNDULATION - 1)) { + for (x in 0..WIDTH) { + val map: Boolean = ( + joise.get( + x / SCALE_X, + y / SCALE_Y + ) == 1.0) + noiseMap[y + TERRAIN_AVERAGE_HEIGHT - (TERRAIN_UNDULATION / 2)].set(x, map) } - - // add interpolated value to map - for (i in perlinMap.indices) { - val perlinPointLeft = perlinSamples[i / perlinSampleDist] - val perlinPointRight = perlinSamples[i / perlinSampleDist + 1] - - perlinMap[i] += Math.round( - interpolateCosine( - (i % perlinSampleDist).toFloat() / perlinSampleDist, perlinPointLeft.toFloat(), perlinPointRight.toFloat()))// using cosine; making tops rounded + } + // fill the area bottom of the above map as 'filled' + for (y in TERRAIN_AVERAGE_HEIGHT + (TERRAIN_UNDULATION / 2)..HEIGHT - 1) { + for (x in 0..WIDTH) { + noiseMap[y].set(x, true) } } - for (k in 0..0) { - for (i in perlinMap.indices) { - // averaging smoothing - if (i > 1 && i < perlinMap.size - 2) { - perlinMap[i] = Math.round( - ((perlinMap[i - 1] + perlinMap[i + 1]) / 2).toFloat()) - } - } - } - - // single bump removal - for (i in perlinMap.indices) { - if (i > 1 && i < perlinMap.size - 2) { - val p1 = perlinMap[i - 1] - val p2 = perlinMap[i] - val p3 = perlinMap[i + 1] - // _-_ / -_- -> ___ / --- - if (p1 == p3 && p1 != p2) { - perlinMap[i] = p1 - } else if (p1 > p3 && p2 > p1) { - perlinMap[i] = p1 - } else if (p3 > p1 && p2 > p3) { - perlinMap[i] = p3 - } else if (p3 > p1 && p2 < p1) { - perlinMap[i] = p1 - } else if (p1 > p3 && p2 < p3) { - perlinMap[i] = p1 - }// ^_- -> ^-- - // -_^ -> --^ - // _^- -> _-- - // -^_ -> --_ - } - } - - return perlinMap + return noiseMap } /** @@ -501,14 +587,14 @@ object MapGenerator { println("[mapgenerator] Shaping world as processed...") // iterate for heightmap - for (x in 0..width - 1) { + for (x in 0..WIDTH - 1) { val medianPosition = TERRAIN_AVERAGE_HEIGHT val pillarOffset = medianPosition - fs[x] // for pillar length - for (i in 0..height - pillarOffset - 1) { + for (i in 0..HEIGHT - pillarOffset - 1) { - if (i < dirtThickness) { + if (i < DIRT_LAYER_DEPTH) { map.setTileTerrain(x, i + pillarOffset, TileNameCode.DIRT) map.setTileWall(x, i + pillarOffset, TileNameCode.DIRT) } else { @@ -520,67 +606,71 @@ object MapGenerator { } } - private fun perturbTerrain() { - val perturbGen = SimplexNoise(TERRAIN_PERTURB_LARGESTFEATURE, TERRAIN_PERTURB_RATE, seed!! xor random.nextLong()) + private fun terrainMapToObjectMap() { + println("[mapgenerator] Shaping world as processed...") + // generate dirt-stone transition line + // use catmull spline + val dirtStoneLine = IntArray(WIDTH) + val POINTS_GAP = 64 // power of two! + val splineControlPoints = Array((WIDTH / POINTS_GAP) + 1, { Pair(0, 0) }) - val perturbMap = Array(height) { FloatArray(width) } + // get spline points + for (x in 0..(WIDTH / POINTS_GAP)) { + for (y in 0..TERRAIN_AVERAGE_HEIGHT + TERRAIN_UNDULATION) { + 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}") + } - val layerWall = map.wallArray - val layerTerrain = map.terrainArray - val newLayerWall = MapLayer(width, height) - val newLayerTerrain = MapLayer(width, height) + // do interpolation + for (x in 0..dirtStoneLine.size) { + val x_1 = x / POINTS_GAP - var lowestNoiseVal = 10000f - var highestNoiseVal = -10000f + val splineX0 = splineControlPoints[ clamp(x_1 - 1, 0, dirtStoneLine.size / POINTS_GAP) ].first + val splineX1 = splineControlPoints[x_1].first + val splineX2 = splineControlPoints[ clamp(x_1 + 1, 0, dirtStoneLine.size / POINTS_GAP) ].first + val splineX3 = splineControlPoints[ clamp(x_1 + 2, 0, dirtStoneLine.size / POINTS_GAP) ].first - for (y in 0..map.height - 1) { - for (x in 0..map.width - 1) { - val noise = perturbGen.getNoise(x, y) // [-1, 1] - perturbMap[y][x] = noise - if (noise < lowestNoiseVal) lowestNoiseVal = noise - if (noise > highestNoiseVal) highestNoiseVal = noise + val splineP0 = splineControlPoints[ clamp(x_1 - 1, 0, dirtStoneLine.size / POINTS_GAP) ].second.toFloat() + val splineP1 = splineControlPoints[x_1].second.toFloat() + val splineP2 = splineControlPoints[ clamp(x_1 + 1, 0, dirtStoneLine.size / POINTS_GAP) ].second.toFloat() + val splineP3 = splineControlPoints[ clamp(x_1 + 2, 0, dirtStoneLine.size / POINTS_GAP) ].second.toFloat() + + if (x in POINTS_GAP - 1..WIDTH - 2 * POINTS_GAP) { + dirtStoneLine[x] = Math.round(FastMath.interpolateCatmullRom( + (x - splineX1) / POINTS_GAP.toFloat(), + 0.01f, + splineP0, + splineP1, + splineP2, + splineP3 + )) + } + else { + interpolateCosine( + (x - splineX1) / POINTS_GAP.toFloat(), + splineP1, + splineP2 + ) } } - // Auto-scale noise [-1, 1] - /** - * See ./work_files/Linear_autoscale.gcx - */ - for (y in 0..height - 1) { - for (x in 0..width - 1) { - val noiseInit = perturbMap[y][x] - val noiseFin = (noiseInit - (highestNoiseVal + lowestNoiseVal) / 2f) * (2f / (highestNoiseVal - lowestNoiseVal)) - - perturbMap[y][x] = noiseFin - } - } - - // Perturb to x-axis, apply to newLayer - for (y in 0..height - 1) { - for (x in 0..width - 1) { - val offsetOrigin = perturbMap[y][x] * 0.5f + 0.5f // [0 , 1] - val offset = Math.round(offsetOrigin * TERRAIN_PERTURB_OFFSETMAX) - - val tileWall = layerWall[y][x] - val tileTerrain = layerTerrain[y][x] - - try { - //newLayerWall.setTile(x + offset, y, tileWall); - //newLayerTerrain.setTile(x + offset, y, tileTerrain); - //layerWall[y][x] = 0; - //layerTerrain[y][x] = 0; - layerWall[y - offset][x] = tileWall - layerTerrain[y - offset][x] = tileTerrain - } catch (e: ArrayIndexOutOfBoundsException) { + // scan vertically + for (x in 0..WIDTH - 1) { + for (y in 0..HEIGHT - 1) { + if (terrainMap[clamp(y + DIRT_LAYER_DEPTH, 0, HEIGHT - 1)].get(x)) { + // map.setTileTerrain(x, y, TileNameCode.DIRT) + // map.setTileWall(x, y, TileNameCode.DIRT) + val tile = + if (y < dirtStoneLine[x]) TileNameCode.DIRT + else TileNameCode.STONE + map.setTileTerrain(x, y, tile) + map.setTileWall(x, y, tile) } - } } - - // set reference (pointer) of original map layer to new layers - //map.overwriteLayerWall(newLayerWall); - //map.overwriteLayerTerrain(newLayerTerrain); - } /* 2. Carve */ @@ -588,8 +678,8 @@ object MapGenerator { private fun carveCave(noisemap: Array, tile: Int, message: String) { println("[mapgenerator] " + message) - for (i in 0..height - 1) { - for (j in 0..width - 1) { + for (i in 0..HEIGHT - 1) { + for (j in 0..WIDTH - 1) { if (noisemap[i][j] > 0.9) { map.setTileTerrain(j, i, tile) } @@ -610,8 +700,8 @@ object MapGenerator { private fun carveByMap(noisemap: Array, scarcity: Float, tile: Int, message: String) { println("[mapgenerator] " + message) - for (i in 0..height - 1) { - for (j in 0..width - 1) { + 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) } @@ -634,8 +724,8 @@ object MapGenerator { private fun fillByMap(noisemap: Array, scarcity: Float, replaceFrom: Int, tile: Int, message: String) { println("[mapgenerator] " + message) - for (i in 0..height - 1) { - for (j in 0..width - 1) { + 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) } @@ -658,8 +748,8 @@ object MapGenerator { private fun fillByMapInverseGradFilter(noisemap: Array, scarcity: Float, replaceFrom: Int, tile: Int, message: String) { println("[mapgenerator] " + message) - for (i in 0..height - 1) { - for (j in 0..width - 1) { + 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) @@ -686,8 +776,8 @@ object MapGenerator { private fun fillByMapNoFilter(noisemap: Array, scarcity: Float, replaceFrom: Int, tile: Int, message: String) { println("[mapgenerator] " + message) - for (i in 0..height - 1) { - for (j in 0..width - 1) { + 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) } @@ -695,15 +785,16 @@ object MapGenerator { } } - private fun fillByMapNoFilterUnderground(noisemap: Array, scarcity: Float, replaceFrom: Int, tile: Int, message: String) { + private fun fillByMapNoFilterUnderground(noisemap: Array, scarcity: Float, replaceFrom: Int, replaceTo: Int, message: String) { println("[mapgenerator] " + message) - for (i in 0..height - 1) { - for (j in 0..width - 1) { + for (i in 0..HEIGHT - 1) { + for (j in 0..WIDTH - 1) { if (noisemap[i][j] > noiseGradientStart * scarcity - && map.getTileFromTerrain(j, i) == replaceFrom - && map.getTileFromWall(j, i) == TileNameCode.STONE) { - map.setTileTerrain(j, i, tile) + && map.getTileFromTerrain(j, i) ?: 0 == replaceFrom + && map.getTileFromWall(j, i) ?: 0 == replaceTo + ) { + map.setTileTerrain(j, i, replaceTo) } } } @@ -712,8 +803,8 @@ object MapGenerator { private fun fillByMap(noisemap: Array, scarcity: Float, replaceFrom: Int, tile: IntArray, message: String) { println("[mapgenerator] " + message) - for (i in 0..height - 1) { - for (j in 0..width - 1) { + 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)]) } @@ -730,11 +821,11 @@ object MapGenerator { } 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 + 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) { + } else if (func_argX >= HEIGHT) { return end } else { return graph_gradient @@ -769,12 +860,12 @@ object MapGenerator { */ 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 + (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) { + } else if (func_argX >= HEIGHT) { return end } else { return graph_gradient @@ -809,12 +900,12 @@ object MapGenerator { */ 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 + (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) { + } else if (func_argX >= HEIGHT) { return end } else { return graph_gradient @@ -848,13 +939,13 @@ object MapGenerator { * @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 + 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) { + } else if (func_argX >= HEIGHT) { return end } else { return graph_gradient @@ -895,8 +986,8 @@ object MapGenerator { private fun floodBottomLava() { println("[mapgenerator] Flooding bottom lava...") - for (i in height * 14 / 15..height - 1) { - for (j in 0..width - 1) { + for (i in HEIGHT * 14 / 15..HEIGHT - 1) { + for (j in 0..WIDTH - 1) { if (map.terrainArray[i][j].toInt() == 0) { map.setTileTerrain(j, i, TileNameCode.LAVA) } @@ -915,17 +1006,16 @@ object MapGenerator { * under another certain level, use background stone with dirt peckles. */ - for (y in TERRAIN_AVERAGE_HEIGHT - MAX_HILL_HEIGHT..TERRAIN_AVERAGE_HEIGHT + MAX_HILL_HEIGHT - 1) { + for (y in TERRAIN_AVERAGE_HEIGHT - TERRAIN_UNDULATION..TERRAIN_AVERAGE_HEIGHT + TERRAIN_UNDULATION - 1) { for (x in 0..map.width - 1) { val thisTile = map.getTileFromTerrain(x, y) for (i in 0..8) { - var nearbyWallTile = -1 - try { - nearbyWallTile = map.getTileFromWall(x + i % 3 - 1, y + i / 3 - 1) - } catch (e: ArrayIndexOutOfBoundsException) { - } + var nearbyWallTile: Int? + nearbyWallTile = map.getTileFromWall(x + i % 3 - 1, y + i / 3 - 1) + + if (nearbyWallTile == null) break; if (i != 4 && thisTile == TileNameCode.DIRT && nearbyWallTile == TileNameCode.AIR) { map.setTileTerrain(x, y, TileNameCode.GRASS) @@ -957,10 +1047,11 @@ object MapGenerator { private fun fillOcean() { val thisSandList = intArrayOf( - TileNameCode.SAND_BEACH, TileNameCode.SAND_BLACK, TileNameCode.SAND_GREEN, - TileNameCode.SAND_BEACH, TileNameCode.SAND_BEACH, TileNameCode.SAND_BLACK - ) - val thisRand = HQRNG(seed!! xor random.nextLong()) + TileNameCode.SAND, TileNameCode.SAND, TileNameCode.SAND, TileNameCode.SAND, + TileNameCode.SAND_WHITE, TileNameCode.SAND_WHITE, TileNameCode.SAND_WHITE, + TileNameCode.SAND_BLACK, TileNameCode.SAND_BLACK, TileNameCode.SAND_GREEN + ) + val thisRand = HQRNG(SEED xor random.nextLong()) val thisSand = thisSandList[thisRand.nextInt(thisSandList.size)] // val thisSand = TileNameCode.SAND_GREEN @@ -968,9 +1059,11 @@ object MapGenerator { "black" else if (thisSand == TileNameCode.SAND_GREEN) "green" + else if (thisSand == TileNameCode.SAND) + "yellow" else "white" - println("[mapgenerator] Beach sand type: " + thisSandStr) + println("[mapgenerator] Beach sand type: $thisSandStr") var ix = 0 while (ix < OCEAN_WIDTH * 1.5) { @@ -1061,12 +1154,12 @@ object MapGenerator { * @return */ private fun getTerrainHeightFromHeightMap(x: Int): Int { - return TERRAIN_AVERAGE_HEIGHT - heightMap[x] + TODO() } - @JvmStatic + fun getGeneratorSeed(): Long { - return seed!! + return SEED } /* Utility */ @@ -1090,9 +1183,9 @@ object MapGenerator { for (pointerX in 0..brushSize - 1) { if (getDistance(j.toFloat(), i.toFloat(), j + pointerX - halfBrushSize, i + pointerY - halfBrushSize) <= FastMath.floor((brushSize / 2).toFloat()) - 1) { if (Math.round(j + pointerX - halfBrushSize) > brushSize - && Math.round(j + pointerX - halfBrushSize) < width - brushSize - && Math.round(i + pointerY - halfBrushSize) > brushSize - && Math.round(i + pointerY - halfBrushSize) < height - brushSize) { + && Math.round(j + pointerX - halfBrushSize) < WIDTH - brushSize + && Math.round(i + pointerY - halfBrushSize) > brushSize + && Math.round(i + pointerY - halfBrushSize) < HEIGHT - brushSize) { if (map.terrainArray[Math.round(i + pointerY - halfBrushSize)][Math.round(j + pointerX - halfBrushSize)] == fillFrom.toByte()) { map.terrainArray[Math.round(i + pointerY - halfBrushSize)][Math.round(j + pointerX - halfBrushSize)] = fill.toByte() } @@ -1102,4 +1195,6 @@ object MapGenerator { } } + private fun clamp(x: Int, min: Int, max: Int): Int = if (x < min) min else if (x > max) max else x + } \ No newline at end of file diff --git a/src/com/Torvald/Terrarum/MapGenerator/SimplexNoise.kt b/src/com/Torvald/Terrarum/MapGenerator/SimplexNoise.kt index 7d998bb42..45c416e5f 100644 --- a/src/com/Torvald/Terrarum/MapGenerator/SimplexNoise.kt +++ b/src/com/Torvald/Terrarum/MapGenerator/SimplexNoise.kt @@ -11,9 +11,7 @@ class SimplexNoise * * * @param seed */ -(internal var largestFeature: - - Int, internal var persistence: Float, internal var seed: Long) { +(internal var largestFeature: Int, internal var persistence: Float, internal var seed: Long) { internal var octaves: Array internal var frequencys: FloatArray diff --git a/src/com/Torvald/Terrarum/SAVE_FORMAT b/src/com/Torvald/Terrarum/SAVE_FORMAT deleted file mode 100644 index 27aa87ba0..000000000 --- a/src/com/Torvald/Terrarum/SAVE_FORMAT +++ /dev/null @@ -1,54 +0,0 @@ -* Save meta - - Binary (for more security) - - Filename : world (with no extension) - - Type Mnemonic Description - - Byte[4] TESV Magic - Byte[n] name Savegame name, UTF-8 - 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 (TEMD data) [32, 214, 42, 3, 76, ...] - - Endianness: Big - -* Actor data - - GZip'd GSON - - Filename : (with no extension) - - -* Prop data - - GZip'd CSV - - Filename : worldinfo2 -- tileprop.csv - worldinfo3 -- itemprop.csv - worldinfo4 -- materialprop.csv - (with no extension) - - -* Human-readable - - Tiles_list.txt -- list of tiles in csv - - Items_list.txt -- list of items in csv - - Materials_list.txt -- list of materials in csv - - - -== How it works == - * If hash discrepancy is detected, (hash of csv in save dir != stored hash || hash of TEMD != stored hash) - printout "Save file corrupted. Continue?" with prompt "Yes/No" - - Directory: - - +--- - --- 2a93bc5fd...f823 Actor data - --- 423bdc838...93bd Actor data - --- Items_list.txt Human-readable - --- Tiles_list.txt Human-readable - --- world save meta - --- worldinfo1 TEMD binary - --- worldinfo2 tileprop - --- worldinfo3 itemprop - --- worldinfo4 materialprop diff --git a/src/com/Torvald/Terrarum/Terrarum.kt b/src/com/Torvald/Terrarum/Terrarum.kt index cdfbab2a6..aa64541c8 100644 --- a/src/com/Torvald/Terrarum/Terrarum.kt +++ b/src/com/Torvald/Terrarum/Terrarum.kt @@ -103,9 +103,9 @@ constructor(gamename: String) : StateBasedGame(gamename) { private lateinit var configDir: String - @JvmStatic fun main(args: Array) { + fun main(args: Array) { try { - appgc = AppGameContainer(Terrarum("terrarum")) + appgc = AppGameContainer(Terrarum("Terrarum")) appgc.setDisplayMode(WIDTH, HEIGHT, false) appgc.setTargetFrameRate(TARGET_INTERNAL_FPS) @@ -327,4 +327,6 @@ constructor(gamename: String) : StateBasedGame(gamename) { return cfg } } -} \ No newline at end of file +} + +fun main(args: Array) = Terrarum.main(args) \ No newline at end of file diff --git a/src/com/Torvald/Terrarum/TileProperties/TileNameCode.kt b/src/com/Torvald/Terrarum/TileProperties/TileNameCode.kt index 6a9950891..cdd85ee22 100644 --- a/src/com/Torvald/Terrarum/TileProperties/TileNameCode.kt +++ b/src/com/Torvald/Terrarum/TileProperties/TileNameCode.kt @@ -26,7 +26,7 @@ object TileNameCode { val TRUNK_BLOODROSE = TilePropCodex.indexDamageToArrayAddr(4, 3) val SAND = TilePropCodex.indexDamageToArrayAddr(5, 0) - val SAND_BEACH = TilePropCodex.indexDamageToArrayAddr(5, 1) + val SAND_WHITE = TilePropCodex.indexDamageToArrayAddr(5, 1) val SAND_RED = TilePropCodex.indexDamageToArrayAddr(5, 2) val SAND_DESERT = TilePropCodex.indexDamageToArrayAddr(5, 3) val SAND_BLACK = TilePropCodex.indexDamageToArrayAddr(5, 4) diff --git a/src/com/Torvald/Terrarum/TileProperties/TilePropCodex.kt b/src/com/Torvald/Terrarum/TileProperties/TilePropCodex.kt index ef614bdf9..affa0d013 100644 --- a/src/com/Torvald/Terrarum/TileProperties/TilePropCodex.kt +++ b/src/com/Torvald/Terrarum/TileProperties/TilePropCodex.kt @@ -55,15 +55,15 @@ class TilePropCodex { return tileProps[indexDamageToArrayAddr(index, damage)] } - fun getProp(rawIndex: Int): TileProp { + fun getProp(rawIndex: Int?): TileProp { try { - tileProps[rawIndex].id + tileProps[rawIndex ?: TileNameCode.STONE].id } catch (e: NullPointerException) { throw NullPointerException("Tile prop with raw id $rawIndex does not exist.") } - return tileProps[rawIndex] + return tileProps[rawIndex ?: TileNameCode.STONE] } private fun setProp(prop: TileProp, record: CSVRecord) { @@ -88,7 +88,7 @@ class TilePropCodex { if (prop.isFluid) prop.movementResistance = intVal(record, "movr") print(formatNum3(prop.id) + ":" + formatNum2(prop.damage)) - println("\t" + prop.name!!) + println("\t" + prop.name) } private fun intVal(rec: CSVRecord, s: String): Int { diff --git a/src/com/Torvald/Terrarum/gameactors/ActorInventory.kt b/src/com/Torvald/Terrarum/gameactors/ActorInventory.kt index 4490e8692..d33b2d793 100644 --- a/src/com/Torvald/Terrarum/gameactors/ActorInventory.kt +++ b/src/com/Torvald/Terrarum/gameactors/ActorInventory.kt @@ -82,6 +82,7 @@ class ActorInventory() { * Get clone of the itemList * @return */ + @Suppress("UNCHECKED_CAST") fun getCopyOfItemList(): Map? { return itemList.clone() as Map } diff --git a/src/com/Torvald/Terrarum/gameactors/ActorWithBody.kt b/src/com/Torvald/Terrarum/gameactors/ActorWithBody.kt index 5cfdf12de..c04c57f27 100644 --- a/src/com/Torvald/Terrarum/gameactors/ActorWithBody.kt +++ b/src/com/Torvald/Terrarum/gameactors/ActorWithBody.kt @@ -7,6 +7,7 @@ import com.torvald.terrarum.mapdrawer.MapDrawer import com.torvald.terrarum.tileproperties.TilePropCodex import com.torvald.spriteanimation.SpriteAnimation import com.jme3.math.FastMath +import com.torvald.terrarum.tileproperties.TileNameCode import org.newdawn.slick.GameContainer import org.newdawn.slick.Graphics @@ -424,7 +425,7 @@ open class ActorWithBody constructor() : Actor, Visible, Glowing { } // evaluate - if (TilePropCodex.getProp(map.getTileFromTerrain(tileX, tileY)).isSolid) { + if (TilePropCodex.getProp(map.getTileFromTerrain(tileX, tileY) ?: TileNameCode.STONE).isSolid) { contactAreaCounter += 1 } } diff --git a/src/com/Torvald/Terrarum/gameactors/CreatureRawInjector.kt b/src/com/Torvald/Terrarum/gameactors/CreatureRawInjector.kt index 379ee684a..418d88617 100644 --- a/src/com/Torvald/Terrarum/gameactors/CreatureRawInjector.kt +++ b/src/com/Torvald/Terrarum/gameactors/CreatureRawInjector.kt @@ -13,13 +13,14 @@ import java.io.IOException */ object CreatureRawInjector { - const val JSONPATH = "./res/raw/" + const val JSONPATH = "./res/raw/creatures/" private const val MULTIPLIER_RAW_ELEM_SUFFIX = "mult" /** * 'Injects' creature raw ActorValue to the ActorValue reference provided. * * @param actorValueRef ActorValue object to be injected. + * @param jsonFileName with extension */ @Throws(IOException::class, SlickException::class) fun inject(actorValueRef: ActorValue, jsonFileName: String) { diff --git a/src/com/Torvald/Terrarum/gameactors/PFSigrid.kt b/src/com/Torvald/Terrarum/gameactors/PFSigrid.kt index ae7f7f3de..d4dd4fdfa 100644 --- a/src/com/Torvald/Terrarum/gameactors/PFSigrid.kt +++ b/src/com/Torvald/Terrarum/gameactors/PFSigrid.kt @@ -4,6 +4,7 @@ import com.torvald.JsonFetcher import com.torvald.terrarum.gameactors.faction.Faction import com.torvald.spriteanimation.SpriteAnimation import com.google.gson.JsonObject +import com.torvald.terrarum.gameactors.faction.FactionFactory import org.newdawn.slick.SlickException import java.io.IOException @@ -13,8 +14,6 @@ import java.io.IOException object PFSigrid { - private val FACTION_PATH = "./res/raw/" - fun create(): Player { val p = Player() @@ -66,27 +65,8 @@ object PFSigrid { p.setPosition((4096 * 16).toFloat(), (300 * 16).toFloat()) - p.faction.add(loadFactioningData("FactionSigrid.json")) + p.faction.add(FactionFactory.create("FactionSigrid.json")) return p } - - private fun loadFactioningData(filename: String): Faction { - var jsonObject: JsonObject = JsonObject() - try { - jsonObject = JsonFetcher.readJson(FACTION_PATH + filename) - } catch (e: IOException) { - e.printStackTrace() - System.exit(-1) - } - - val faction = Faction(jsonObject.get("factionname").asString) - - jsonObject.get("factionamicable").asJsonArray.forEach { jobj -> faction.addFactionAmicable(jobj.asString) } - jsonObject.get("factionneutral").asJsonArray.forEach { jobj -> faction.addFactionNeutral(jobj.asString) } - jsonObject.get("factionhostile").asJsonArray.forEach { jobj -> faction.addFactionHostile(jobj.asString) } - jsonObject.get("factionfearful").asJsonArray.forEach { jobj -> faction.addFactionFearful(jobj.asString) } - - return faction - } } diff --git a/src/com/Torvald/Terrarum/gameactors/faction/Faction.kt b/src/com/Torvald/Terrarum/gameactors/faction/Faction.kt index 558babda1..0024773d8 100644 --- a/src/com/Torvald/Terrarum/gameactors/faction/Faction.kt +++ b/src/com/Torvald/Terrarum/gameactors/faction/Faction.kt @@ -1,5 +1,6 @@ package com.torvald.terrarum.gameactors.faction +import com.torvald.random.HQRNG import java.util.HashSet /** @@ -12,6 +13,7 @@ class Faction(factionName: String) { lateinit var factionNeutral: HashSet lateinit var factionHostile: HashSet lateinit var factionFearful: HashSet + var factionID: Long = HQRNG().nextLong() init { this.factionName = factionName diff --git a/src/com/jme3/math/FastMath.java b/src/com/jme3/math/FastMath.java index 5455552e8..9dc9066da 100644 --- a/src/com/jme3/math/FastMath.java +++ b/src/com/jme3/math/FastMath.java @@ -29,7 +29,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * This source is a custom modification of the original code. + * This source, used in the project 'Terrarum' is a derivative of the original code. + * I claim no ownership to this FastMath module. --Torvald */ package com.jme3.math; diff --git a/src/com/torvald/terrarum/ABOUT.md b/src/com/torvald/terrarum/ABOUT.md new file mode 100644 index 000000000..f92375eb7 --- /dev/null +++ b/src/com/torvald/terrarum/ABOUT.md @@ -0,0 +1,132 @@ +## About gamemaking ## + +### CHALLENGING, NOT PUNISHING ### +https://www.youtube.com/watch?v=ea6UuRTjkKs + +1. CONSISTENT RULES + - No arbitrary unstoppable death + +2. Player's skill involved + - Can play around, not restart + +3. Usability of in-game tools + - Players should be able to 'regret' their strategy and adjust. + +4. Comfortable control + +5. Make players overcome the challenge, not defeating them + +6. Let players have "aha" moment when they failed. + - Make them hungry to retry with new strategies. + - Some small things they've could done differently + - e.g. "One-big-hit didn't worked, may I should've picked up high DPS one" + + +### MORE DEPTH, LESS COMPLEXITY ### +https://www.youtube.com/watch?v=jVL4st0blGU + +1. Memorise less! + - Less burden to, even starting the game + - Start with gentle learning curve, getting slowly steep + - Intuitive UX (UI, control, ...) + - Good tutorial = lessens complexity + +2. Intuitive! + +3. Calculations per second + - reduce! + +4. Players have to know everything to even begin the play ### FAIL (irreducible complexity) + - Make them get familiar with rules of the game + - Dwarf Fortress failed this! + + +### Lots of things players can play with (aka don't make them bored) ### + +- Combat, battle, building, mechanics, adventure, dungeon explore, spelunking +- Not scaled; easy combat, tough combat, tedious combat, etc. + + +### Achieving perfect imbalance ### +https://www.youtube.com/watch?v=e31OSVZF77w + +- Make sure no matter how you skilled, your playable character cannot be good at everything +- Give players __wide pool of options__ to solve problem + (kill the boss, defend their adobe, fast transportation, etc.) + + +**_What feeling do you want to convey?_** + + +### Always think WHY you want to add _something_ on the game ### + +- e.g. Why are you adding RPG leveling system? What it would do to the players? How would they play with? + + +See also: *HEARTS, CLUBS, DIAMONDS, SPADES: PLAYERS WHO SUIT MUDS* + + +## About this very game ## + +### Friendlier version of Dwarf Fortress Adventure mode ### + +- Yet _lots of fun_ +- Add Fortress mode features by 'make your own settling' +- Hard to actually die, but once you die, you're done. + + Config: imtooyoungtodie for easy mode + +- Genre: Adventure, Open world (towns in RPG, building, town managing (conquer existing one or + you build one and persuade existing people to move in) -> See Dwarf Fortress and Animal Crossing) + + * Adventure: adventure this vast—5,5 km wide—world, discover new (and good/horrible) things + + * Open world: + - Building: building your own houses, structures, etc. + - Town managing: + 1. Build your own little hamlet and manage it + or- + 2. Conquer existing one and become a ruler + The town is a special hamlet that can be tailored for your taste + - Survival: + mobs will trying to attack your assets (yourself, your hamlet, your people) + + + +### Side view ### + +### Interact menu w/ mouse right ### + +### Pixelated sprites ### +- Use 2x sprites if rotating does not work well + + +### User experience ### + +* Indicative mouse cursor + + +### Game mechanics ### + +* 24 pixels == 1 metre + + +### Purpose of the game ### + +* Boss + - Will be mentioned/shown as absolute _evil_. + - But actually is not. + +* Theme + - Is an evil really really is what we think? + - Is there a thing as 'absolute evil'? + +* Boss character + - From debugger character + - Name key: "Sigriðr hinn Dróttningin" (can be changed) + * Little setting + - A ruler, hated by people + +* Mechanics + - Beating boss does not ends the game, but grants an ability to + create new character as it. + \ No newline at end of file diff --git a/src/com/torvald/terrarum/COPYING.md b/src/com/torvald/terrarum/COPYING.md new file mode 100644 index 000000000..f7a74d276 --- /dev/null +++ b/src/com/torvald/terrarum/COPYING.md @@ -0,0 +1,9 @@ +* *Terrarum* by Torvald + Copyright 2015-2016 Torvald. All rights reserved. + mailto: skyhi14 *64* __115875741922660__ *46* __6516589__ + +* *Simplex Noise Generator*, version 2012-03-09 by Stefan Gustavson + Released as public domain + +* *Joise* modular noise library + Copyright (C) 2013 Jason Taylor. Released as open-source under Apache License, Version 2.0. diff --git a/src/com/torvald/terrarum/MECHNANICS.md b/src/com/torvald/terrarum/MECHNANICS.md new file mode 100644 index 000000000..bb9712dff --- /dev/null +++ b/src/com/torvald/terrarum/MECHNANICS.md @@ -0,0 +1,125 @@ + +## Weapon tier ## + + Natural / Common Stone -> Copper -> Iron -> Silver -> Titanium + Forging --------------> Steel --------^ + Exotic ('elven') Glass Aurichalcum + Special (something 'adamant') ??? (Use material spec of CNT, tensile strength 180 GPa) + +* Metal graphics + - Gold: Hue 43, low Saturation + - Aurichalcum: Hue 43, mid-high Saturation + - Copper: Hue 33, + - Copper rust: Hue 160 + - Iron rust: Hue 21 + + +## Size variation ## + +Race base weapon/tool size <- 10 [kg] +Size tolerance <- (50% * str/1000), or say, 20% + +If the size is bigger than tolerable, weapon speed severely slows down, tools become unusable + if use time >* 0.75 second, the weapon/tool cannot be equipped. +Small weapons/tools gains no (dis)advantage + +When drawing: scale by (craftedWeaponSize / baseWeaponSize) + +Crafted tool/weapon size is dependent to the baseRaceMass. + + +## Gemstone tier ## + +Topaz -> R·G·B -> Diamond·Amethyst + + +## Colouring ## + +Natural: Use 4096 +Magical/Surreal: Use 24 Bits + +* Colouring of potion + - Randomised, roguelike fashion + - Choose Col(R40, G40, B40) from set of finite cards: + 39, 39, 19, 19, 0, 0 + - MULTIPLY blend chosen colour with white texture + + +## Roguelike identity ## + +* Randomised things + - E.g. potion + Lime-coloured potion + First play: "Potion (???)" + After drank: "Potion (Healing)" is revealed. + + Second (new) play: "Potion (???)" + After drank: "Potion (Neurotoxin)" is revealed. + + +## Making sprite ## + +* Layers + - (Optional) Glow + - (Optional) Hair foreground + - Right arm dress + - Right arm body + - Dress + - Boots + - Body + - (Optional) Hair accessory + - Hair + - Head + - Left arm dress + - Left arm body + - (Optional) SFX + +* Size + - Regular sprite 'height' (hitbox height) : 40 px + - Apparent height may vary + + +## Chargen ## + +* Select hair, colours, then compile them into single spritesheet + +* NO gender distinction, but have masculine/neutral/feminine looks (in clothing, hairstyles, etc.) + +* Colour: 4096 colours (12-bit 0x000 - 0xFFF) + +* 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) + + +## (De)serialisation ## + +see SAVE_FORMAT.md + + +## Actor as universal tool ## + +* Utility tiles that have states (e.g. noteblock) are implemented using Actor. + + +## NPC Killing ## + +* AI: + Attacked first: Warn player to not attack + Attacked second: The NPC becomes hostile until player sheathe the weapon + Attacked thrice: All the NPCs within the same faction become hostile until the player is away + + +## Ownership of lands ## + +* Codex of Real Estate → assign owner to the tiles → copy the information to the NPC instance + \ No newline at end of file diff --git a/src/com/torvald/terrarum/SAVE_FORMAT.md b/src/com/torvald/terrarum/SAVE_FORMAT.md new file mode 100644 index 000000000..080b4d9dd --- /dev/null +++ b/src/com/torvald/terrarum/SAVE_FORMAT.md @@ -0,0 +1,57 @@ +## Format ## + +* Save meta + - Binary (for more security) + - Filename : world (with no extension) + + |Type |Mnemonic |Description | + |------------|------------|---------------------------------------| + |Byte[4] |TESV |Magic | + |Byte[n] |name |Savegame name, UTF-8 | + |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| + + Endianness: Big + +* Actor/Faction data + - GZip'd GSON + - Filename : (refid) (with no extension) + + +* Prop data + - GZip'd CSV + - Filename : worldinfo2 -- tileprop.csv + worldinfo3 -- itemprop.csv + worldinfo4 -- materialprop.csv + (with no extension) + + +* Human-readable + - Tiles_list.txt -- list of tiles in csv + - Items_list.txt -- list of items in csv + - Materials_list.txt -- list of materials in csv + + + +## 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" + +Directory: + + +--- + --- 2a93bc5fd...f823 Actor/Faction/etc. data + --- 423bdc838...93bd Actor/Faction/etc. data + --- Items_list.txt Human-readable + --- Materials_list.txt Human-redable + --- Tiles_list.txt Human-readable + --- world save meta (binary) + --- worldinfo1 TEMD (binary) + --- worldinfo2 tileprop + --- worldinfo3 itemprop + --- worldinfo4 materialprop diff --git a/src/com/torvald/terrarum/console/ExportMap.kt b/src/com/torvald/terrarum/console/ExportMap.kt index 03e077d28..8b9e65e8b 100644 --- a/src/com/torvald/terrarum/console/ExportMap.kt +++ b/src/com/torvald/terrarum/console/ExportMap.kt @@ -4,12 +4,8 @@ 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 +import java.util.HashMap /** * Created by minjaesong on 16-01-17. @@ -19,7 +15,7 @@ class ExportMap : ConsoleCommand { //private var mapData: ByteArray? = null // private var mapDataPointer = 0 - private val colorTable = Hashtable() + private val colorTable = HashMap() override fun execute(args: Array) { if (args.size == 2) { @@ -29,8 +25,8 @@ class ExportMap : ConsoleCommand { var mapDataPointer = 0 for (tile in Terrarum.game.map.layerTerrain) { - val colArray = (colorTable as java.util.Map) - .getOrDefault(tile, Col4096(0xFFF)).toByteArray() + val colArray = (colorTable as Map) + .getOrElse(tile, { Col4096(0xFFF) }).toByteArray() for (i in 0..2) { mapData[mapDataPointer + i] = colArray[i] diff --git a/src/com/torvald/terrarum/console/GetFactioning.kt b/src/com/torvald/terrarum/console/GetFactioning.kt index 49b31ef8b..30ffd0688 100644 --- a/src/com/torvald/terrarum/console/GetFactioning.kt +++ b/src/com/torvald/terrarum/console/GetFactioning.kt @@ -20,8 +20,8 @@ class GetFactioning : ConsoleCommand { // get all factioning data of player val factionSet = Terrarum.game.player.faction - if (factionSet == null) { - echo.execute("The actor has null faction set.") + if (factionSet.isEmpty()) { + echo.execute("The actor has empty faction set.") return } @@ -29,7 +29,7 @@ class GetFactioning : ConsoleCommand { echo.execute(count.toString() + Lang.pluralise(" faction", count) + " assigned.") for (faction in factionSet) { - echo.execute("faction \"" + faction.factionName + "\"") + echo.execute("faction “${faction.factionName}”") echo.execute(" Amicable") faction.factionAmicable.forEach { s -> echo.execute(PRINT_INDENTATION + s) } diff --git a/src/com/torvald/terrarum/console/Help.kt b/src/com/torvald/terrarum/console/Help.kt index dc9bfc9d2..e262852a1 100644 --- a/src/com/torvald/terrarum/console/Help.kt +++ b/src/com/torvald/terrarum/console/Help.kt @@ -1,5 +1,6 @@ package com.torvald.terrarum.console +import com.torvald.terrarum.Terrarum import com.torvald.terrarum.langpack.Lang /** @@ -9,13 +10,19 @@ class Help : ConsoleCommand { override fun execute(args: Array) { val echo = Echo() if (args.size == 1) { - for (i in 1..6) echo.execute(Lang["HELP_OTF_MAIN_TEXT_$i"]) + for (i in 1..6) echo.execute(Lang["HELP_OTF_TEXT_$i"]) } else if (args[1].toLowerCase() == "slow") { - for (i in 1..4) echo.execute(Lang["HELP_OTF_SLOW_TEXT_$i"]) + 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"]) } else { - for (i in 1..6) echo.execute(Lang["HELP_OTF_MAIN_TEXT_$i"]) + for (i in 1..6) echo.execute(Lang["HELP_OTF_MAIN_$i"]) } } diff --git a/src/com/Torvald/Terrarum/gameactors/faction/FactionRelatorFactory.kt b/src/com/torvald/terrarum/gameactors/faction/FactionFactory.kt similarity index 83% rename from src/com/Torvald/Terrarum/gameactors/faction/FactionRelatorFactory.kt rename to src/com/torvald/terrarum/gameactors/faction/FactionFactory.kt index d8335bf07..ce78a8f89 100644 --- a/src/com/Torvald/Terrarum/gameactors/faction/FactionRelatorFactory.kt +++ b/src/com/torvald/terrarum/gameactors/faction/FactionFactory.kt @@ -8,10 +8,15 @@ import java.io.IOException /** * Created by minjaesong on 16-02-15. */ -class FactionRelatorFactory { +object FactionFactory { + const val JSONPATH = "./res/raw/factions/" + + /** + * @param filename with extension + */ @Throws(IOException::class) - fun build(filename: String): Faction { + fun create(filename: String): Faction { val jsonObj = JsonFetcher.readJson(JSONPATH + filename) val factionObj = Faction(jsonObj.get("factionname").asString) @@ -23,10 +28,4 @@ class FactionRelatorFactory { return factionObj } - - companion object { - - val JSONPATH = "./res/raw/" - } - } diff --git a/src/com/torvald/terrarum/gameactors/scheduler/NPCSchedule.kt b/src/com/torvald/terrarum/gameactors/scheduler/NPCSchedule.kt new file mode 100644 index 000000000..55135533b --- /dev/null +++ b/src/com/torvald/terrarum/gameactors/scheduler/NPCSchedule.kt @@ -0,0 +1,8 @@ +package com.torvald.terrarum.gameactors.scheduler + +/** + * Ultima-like NPC scheduler + * Created by minjaesong on 16-03-26. + */ +interface NPCSchedule { +} \ No newline at end of file diff --git a/src/com/torvald/terrarum/realestate/RealEstateCodex.kt b/src/com/torvald/terrarum/realestate/RealEstateCodex.kt new file mode 100644 index 000000000..c8e0a4d0b --- /dev/null +++ b/src/com/torvald/terrarum/realestate/RealEstateCodex.kt @@ -0,0 +1,27 @@ +package com.torvald.terrarum.realestate + +import java.io.Serializable +import java.util.* + +/** + * Created by minjaesong on 16-03-27. + */ +object RealEstateCodex { + /** + * HashMap + * + * Note that a tile can have only ONE owner (as an Actor or Faction ID) + */ + private var ownershipRegistry: HashMap = HashMap() + + fun setOwner(tileX: Int, tileY: Int, refID: Long) { + ownershipRegistry[RealEstateUtility.getAbsoluteTileNumber(tileX, tileY)] = refID + } + + fun removeOwner(tileX: Int, tileY: Int) { + ownershipRegistry.remove(RealEstateUtility.getAbsoluteTileNumber(tileX, tileY)) + } + + fun getOwner(tileX: Int, tileY: Int): Long? = + ownershipRegistry[RealEstateUtility.getAbsoluteTileNumber(tileX, tileY)] +} \ No newline at end of file diff --git a/src/com/torvald/terrarum/realestate/RealEstateUtility.kt b/src/com/torvald/terrarum/realestate/RealEstateUtility.kt new file mode 100644 index 000000000..c271568f8 --- /dev/null +++ b/src/com/torvald/terrarum/realestate/RealEstateUtility.kt @@ -0,0 +1,14 @@ +package com.torvald.terrarum.realestate + +import com.torvald.terrarum.Terrarum + +/** + * Created by minjaesong on 16-03-27. + */ +object RealEstateUtility { + fun getAbsoluteTileNumber(x: Int, y: Int): Long = + (Terrarum.game.map.width * y).toLong() + x + + fun resolveAbsoluteTileNumber(t: Long): Pair = + Pair((t % Terrarum.game.map.width).toInt(), (t / Terrarum.game.map.width).toInt()) +} \ No newline at end of file diff --git a/src/com/torvald/terrarum/tilestats/TileStat.kt b/src/com/torvald/terrarum/tilestats/TileStats.kt similarity index 95% rename from src/com/torvald/terrarum/tilestats/TileStat.kt rename to src/com/torvald/terrarum/tilestats/TileStats.kt index 3cf54f08b..40d83f589 100644 --- a/src/com/torvald/terrarum/tilestats/TileStat.kt +++ b/src/com/torvald/terrarum/tilestats/TileStats.kt @@ -13,7 +13,7 @@ import java.util.Arrays /** * Created by minjaesong on 16-02-01. */ -object TileStat { +object TileStats { private val tilestat = ShortArray(GameMap.TILES_SUPPORTED) @@ -47,8 +47,8 @@ object TileStat { for (x in for_x_start..for_x_end - 1) { val tileWall = map.getTileFromWall(x, y) val tileTerrain = map.getTileFromTerrain(x, y) - ++tilestat[tileWall] - ++tilestat[tileTerrain] + ++tilestat[tileWall ?: 0] + ++tilestat[tileTerrain ?: 0] } } } diff --git a/src/com/torvald/terrarum/ui/BasicDebugInfoWindow.kt b/src/com/torvald/terrarum/ui/BasicDebugInfoWindow.kt index a671dbbec..f6b763a5c 100644 --- a/src/com/torvald/terrarum/ui/BasicDebugInfoWindow.kt +++ b/src/com/torvald/terrarum/ui/BasicDebugInfoWindow.kt @@ -32,7 +32,7 @@ class BasicDebugInfoWindow : UICanvas { } - override fun update(gc: GameContainer, delta_t: Int) { + override fun update(gc: GameContainer, delta: Int) { val player = Terrarum.game.player val hitbox = player.hitbox!! @@ -80,32 +80,26 @@ class BasicDebugInfoWindow : UICanvas { val lightVal: String var mtX = mouseTileX.toString() var mtY = mouseTileY.toString() - try { - val valRaw = LightmapRenderer.getValueFromMap(mouseTileX, mouseTileY) - val rawR = LightmapRenderer.getRawR(valRaw) - val rawG = LightmapRenderer.getRawG(valRaw) - val rawB = LightmapRenderer.getRawB(valRaw) - lightVal = valRaw.toInt().toString() + " (" + + val valRaw = LightmapRenderer.getValueFromMap(mouseTileX, mouseTileY) ?: -1 + val rawR = LightmapRenderer.getRawR(valRaw) + val rawG = LightmapRenderer.getRawG(valRaw) + val rawB = LightmapRenderer.getRawB(valRaw) + lightVal = if (valRaw == -1) + "—" + else + valRaw.toInt().toString() + " (" + rawR.toString() + " " + rawG.toString() + " " + rawB.toString() + ")" - } catch (e: ArrayIndexOutOfBoundsException) { - lightVal = "out of bounds" - mtX = "---" - mtY = "---" - } + printLine(g, 7, "light at cursor : " + lightVal) val tileNo: String - try { - val tileNumRaw = Terrarum.game.map.getTileFromTerrain(mouseTileX, mouseTileY) - val tilenum = tileNumRaw / PairedMapLayer.RANGE - val tiledmg = tileNumRaw % PairedMapLayer.RANGE - tileNo = "$tilenum:$tiledmg" - } catch (e: ArrayIndexOutOfBoundsException) { - tileNo = "-" - } + val tileNumRaw = Terrarum.game.map.getTileFromTerrain(mouseTileX, mouseTileY) ?: -1 + val tilenum = tileNumRaw / PairedMapLayer.RANGE + val tiledmg = tileNumRaw % PairedMapLayer.RANGE + tileNo = if (tileNumRaw == -1) "—" else "$tilenum:$tiledmg" printLine(g, 8, "tile at cursor : $tileNo ($mtX, $mtY)") diff --git a/src/com/torvald/terrarum/ui/ConsoleWindow.kt b/src/com/torvald/terrarum/ui/ConsoleWindow.kt index 8d518c173..d0afa35c6 100644 --- a/src/com/torvald/terrarum/ui/ConsoleWindow.kt +++ b/src/com/torvald/terrarum/ui/ConsoleWindow.kt @@ -43,7 +43,7 @@ class ConsoleWindow : UICanvas, UITypable { reset() } - override fun update(gc: GameContainer, delta_t: Int) { + override fun update(gc: GameContainer, delta: Int) { } diff --git a/src/com/torvald/terrarum/ui/MessageWindow.kt b/src/com/torvald/terrarum/ui/MessageWindow.kt index 08381a1e4..d3a4e0a56 100644 --- a/src/com/torvald/terrarum/ui/MessageWindow.kt +++ b/src/com/torvald/terrarum/ui/MessageWindow.kt @@ -53,7 +53,7 @@ constructor(override var width: Int, isBlackVariant: Boolean) : UICanvas { this.messagesList = messagesList } - override fun update(gc: GameContainer, delta_t: Int) { + override fun update(gc: GameContainer, delta: Int) { }