From 59c144d1b18775cb8b98b257705ea92054eb57f3 Mon Sep 17 00:00:00 2001 From: BenjaminAmos <24301287+BenjaminAmos@users.noreply.github.com> Date: Fri, 7 Apr 2023 11:10:05 +0100 Subject: [PATCH 01/24] build: update groovy wrapper for Gradle 7 (#680) --- gradle/wrapper/groovy-wrapper.jar | Bin 5280 -> 5499 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/gradle/wrapper/groovy-wrapper.jar b/gradle/wrapper/groovy-wrapper.jar index 7fadbd5150cc523b5104c87aabab138320b42805..c17384dc4da4a601bf937dc324f408b332ba03b6 100644 GIT binary patch delta 4847 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 ArvLx| delta 4623 zcmZ9QXE+-S+lHyCO(g_HwPuLDSJf!m+I!ThQL{!7qa{TUv1-SxmDb)PN~$Po)~H=8 zQ6m(g)p)G;ectEzj`#b%`_FaX*Pr|Ed7Nh=#lnondKA}b$;haw$*whgG)`j_ByUTT z)4Tqk1Agb9tPuJqrzIHw?gJwy9cHP>$g*!{+$2|m6v82V@Q_QbvMXovvNFiqI3l32b#k683mq>vYSHEe5EeVf>vMDgDfq9*n>hBpuT}BQo}czfTGgo=*~T zQ$-gu9HdO)&-w`z(rWBI@hq>{c}yBud6L&$qA!!8Q}IA)wMr*8H37x9*+dRX8rS~A z1!{4`X`m+YnE92)sAFb;$v`up_ae>>L&Xof4j2LgqGOA?aY80YCeg5U1o#|pEWpDeXP^m_JgoxZzS{FTWLA%=CPdUvH>@bfmK7r&2I&& z*tTzojL3_7Obce$@hJpMrEQRYm3(2Hw9&wTm#F*uoI@XbZ2RRnMW!FW|3Wk0VvEqG z+rBVIytR7`s}Aw-v_|dctu~7{L;)Dh5&Y?o6p!!o>Nx0j-47uvU5Hczi8kPYjF6A} z12oot8~`iAAYW`L@@BzT5O%w#%?Q&!bXB~#DknPqP{z;ybVl%Mr?yKVin_xio>lw$?)BO>DK5Rs1}aadAbQhhb)#>YzB z6OufnFJ#tCHvHU4J4xhY%*gljipXo2DyaD@wy(_HtVeu!_fU4%S4RDRh+Rk?gnetx zVXA@hiIR!4NF;(s>^UZ>5&@89bEaap%^Yd$SZr_a?UpqdYhlTIbS`i`VwwQ}C zQxK%eyVwIYT8do7X=mHCBen0I10o0a8sJ|}vDP71juEDsx(ug_>8v(2pThd8(yhHh zYr~euMnQHFRUeoH)2lfrUhw!750~ZP3lChKE%d6(1Z+bBEy8wgr8>E^ZBuLMt=3xj zMu^<=1#j;=CHpSJvN5rpH!^mQ3>vF-@~xYDj%KsPQ)A?U4C^N!tq_n4cBzB6J*;I; zY@h{HkY&ow!*+5%ia)#(UyeLQrzqUP+Toz|u*mX3q$z zuNrVqph%_OU%}SWJP%&?mwL_^;@!wX_c^D2QNLE?oRJ`mFeG5LOl5)IP)NtfFJCvDT~PBIp~i;tN?%ssj7a&&!9#f( z70dFA7lvpUmNQSg&cMT=dGohI>yZGShhF9Rl6&Gb+;_eyXi!DBl+2;>mqXhYPtM&j z=T%6{8B&h6v8XiE7%Tto;Ar;4Q0sRMHFD`V$cpHd>r$A-nau}(!thfSqXq0un8rgK zWp4maw`qaEc*(fZLo1AR`~_Fv?Ev6DzT&TI7#=2=|K^Um1iC`>f>WAh3e-2(=qozG z!4RY!6G-hg5M4OwZ)JWmTQcrZ-le9T8rQgAZT#5!K2@s%_;*}gsT4?bJ;hpb(Ofgo zPZ5-|!qJtoZGC4kUAUyxDrE>j!#QxR^At;T6~!R%jT5}`H2nrSQV-C^qIQ~l(tnM# zMD)UpB`WE#%q0z2(~{QqC|ZUh&Cg~1ymVHW!Q)WC!TJF@(i&r2BoPq*mBa4jW%Zq6jw|IZO0; z(0!R+y}JRgTd0WiE3adIsoRa95@)p74`D|Q2#rMt-TOI*l8kp>_x<2HosIK&j>;Uo z*)dcLcjHQ%J5TB^k#?oa3}iGWyvV(B#c^o-fD=r3xa(h zite9~R4hsMkiAbU0BH8arKX?t!-RrWAl=szmni0fPrwOkzfXGO_s&o0E=}!?D&)%& zD|ZA7gnPT<)6c*iJT|7;>1l4X(uz7H_ABW_#uPK#BTKbI=iu}fGO;ZpXezn|M(c9U z6gHv2cgXYoKqELDV)D|vnK#e=6!ux^8@<0Fbc|0*KHk-xrf_nZ>+!Zo$r*26XX!nG za&b*Y2OY^n)mRGF_f6AuO8cC|-kA3Af|7?T1e&SYuo8Gf9sUkX+rJ&>k&3S`U`1YV zzy=*}y2O(Dj~#|plmD#mT#^4@Oc*LqCex-NBeP~DBO@0{TLWc?(+a{y0pz-OU%LVM zhQUt2PxFlO%&5?{ThtqGn4a9(8Qp=GK$~Z-$p~oa$4ugF%7gwhmM$JoN+8M{c1UiQo|Z<`pnT$Q)5B`_ z8>i*`H6BYsB&8z1rY7{KCiWXq--(O>yan{VXH`x53MPrF3E_`vKO9ohBtn0;1;bTR z>3;>E+}NpD_Oi$rId@sPP$s)bv^@>r6&8ug1Gq z)qIavkWyp%gmdendUt*hLn|i{lg$nq*l!M_Hs_E6yr<@u_Yqy02odz$Ax0>fgpvI; zTSDCBbg|4N1~Pk&aEveMo-DdDi`s9@=QNczPRQEN?>I3SFNpIQsz96vz95WG1lz%I z*iY^K>LF8QqusPjw>Pj@&MT+8IsPxVb`bk0K71m5ioB}b-VGWBDmn^NMPQ=^*Q1oF z-`ac0{p$re7GOu6=MC_&e?O&Ne!-D8Q9GgTr!dDqY-6dur;^doGOhITv+!ShhleDXJcyJG=Zta7tpUsQ1W{6BR7@wO?kWd6$cEMXY&0=H(Mz3Fk-vXsriIX&J zQv43Cw|K?jSVEPU%G&HCubVT@?_JwBTfpmd48~XBs{aQ|9^Ljbjg)4c5u@3?N{uP| zH>9*757s)RKfcGEk;spo{$daE95T^)+|NYhKDqLJMQIpQ2IRfOPJlw_)JmNtx;r46}in&>v;Jn@|Mcp_ann5+11?JSEu zQmo|k!|mlEWM<1lfSTK;lFrqQ?yTZXciN>)LsUbYwk_iByKXpKzTdQ&&l% zt81j@a)zQH{N}7ar!dH+;K{{B_*2kym*fa39tp!aN?+FEn9p?w%0w>pQXi&^jHL~4 zcW|Tt3)Ko8u$6GuFBJ8ebE<>0Z}*~J&WuwZN@OK0&AWfLYoSSrRDw`no> zt&5mdA=|i@IjetLS7tFvM<|REJ=rQo7cu7%)X1TZK+hlzR3>sk4>JWP&+!hnz#G? z_-iN=R2Bo;I9B;t*-9ki2>pe>MbX~he@110g3HljB!fLCr{uFYqIVzzsZwWmwlHJhget$0ArR4@w zL;HQfR}=KK3|#hQJ8a*0Uk{UvvE472Gu@Y9dl?aFWOgf9j5Pzb%6sN!3X!%}&yMvJ zeeBZs7IF!yUtLm75O98BruXA{hV^18DeE15Hp3}IrebTmbAb)@NsL33=jf%7|L%25 z*M@ZU>M0MD{7Z#bTvih!5YKIqa0vuV+oPN>uYtUJGWJ=xF9UZ2=#LY3P|cvH&u8pB z{H%e}eG(ZskA%!W?erZDV2bnqlwu!el&=-!E-;13cjQ%LJN=>rmmUtI)=P-NZtY*vg^ zzNJOd>htl{*wPKcuwI?WlEfW&Zj8sskysO}VOj2#_p7_Bi?X+6qJsPV*HtmvN{S!( zoBeaPl}kd}{UUC0PR*kRT&7|3L0d5>&T*%a2?9-v9U5V|IxFjYKea!4dug*H>8F;P zK}5#9R8(8FjXl(`_##@YDvqN$*ARgGW_BH16Q|p+`e9}a!>8hXf$YIXU-C=n}nnrSVod>cgz7Ao}o zewQWxv-o;pQy2A$fku2IoJQ^^I$WidE6VLnwlO_Vu8mZFvvZZqHgC9`wn1^{{7zq( z|BQ_yjZsra(fNI2J@RWT6#tbn896{%^0tgop!$C_OvX(X@qZRg7P)_xmn`@GznK|e hF}w4(toh%lCPMb#DUafzNn2;lFk}_FQ3Lq9{}-_d;CBE3 From 59456019c84bf23c5c71e3d78e57d9166a5751b9 Mon Sep 17 00:00:00 2001 From: Benjamin Amos Date: Mon, 17 Apr 2023 18:08:12 +0100 Subject: [PATCH 02/24] fix: fix pause key not pausing the game --- .../org/destinationsol/game/screens/MainGameScreen.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java b/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java index 855dbdfa5..11dfd84ce 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java +++ b/engine/src/main/java/org/destinationsol/game/screens/MainGameScreen.java @@ -46,7 +46,6 @@ public class MainGameScreen extends SolUiBaseScreen { static final float HELPER_ROW_1 = 1 - 3f * CELL_SZ; private final ShipUiControl shipControl; - private final SolUiControl pauseControl; private final CameraKeyboardControl cameraControl; private final SolApplication solApplication; @@ -75,8 +74,6 @@ public class MainGameScreen extends SolUiBaseScreen { break; } - pauseControl = new SolUiControl(null, true, gameOptions.getKeyPause()); - controls.add(pauseControl); cameraControl = new CameraKeyboardControl(gameOptions, controls); } @@ -125,14 +122,9 @@ public void updateCustom(SolApplication solApplication, SolInputManager.InputPoi if (solApplication.getNuiManager().hasScreenOfType(ConsoleScreen.class)) { controls.forEach(x -> x.setEnabled(false)); } else if (!nuiManager.hasScreen(screens.menuScreen)) { - game.setPaused(false); controls.forEach(x -> x.setEnabled(true)); } - if (pauseControl.isJustOff()) { - game.setPaused(!game.isPaused()); - } - for (SolUiScreen screen : gameOverlayScreens) { screen.updateCustom(solApplication, inputPointers, clickedOutside); } From d152de8d2319ec389e9e1f4d4dc0315d9035dc0b Mon Sep 17 00:00:00 2001 From: Benjamin Amos Date: Sat, 22 Apr 2023 13:54:53 +0100 Subject: [PATCH 03/24] feat(ui): separate ability icons from their charges --- .../org/destinationsol/game/AbilityCommonConfig.java | 9 +++++++-- .../destinationsol/ui/nui/screens/MainGameScreen.java | 10 ++++++++-- .../assets/schemas/schemaAbilitiesConfig.json | 5 +++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/engine/src/main/java/org/destinationsol/game/AbilityCommonConfig.java b/engine/src/main/java/org/destinationsol/game/AbilityCommonConfig.java index 752b55592..bdff810a7 100644 --- a/engine/src/main/java/org/destinationsol/game/AbilityCommonConfig.java +++ b/engine/src/main/java/org/destinationsol/game/AbilityCommonConfig.java @@ -15,6 +15,8 @@ */ package org.destinationsol.game; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import org.destinationsol.assets.Assets; import org.destinationsol.assets.sound.OggSound; import org.destinationsol.assets.sound.OggSoundManager; import org.destinationsol.assets.sound.PlayableSound; @@ -23,10 +25,12 @@ import org.json.JSONObject; public class AbilityCommonConfig { + public final TextureAtlas.AtlasRegion icon; public final EffectConfig effect; public final PlayableSound activatedSound; - public AbilityCommonConfig(EffectConfig effect, PlayableSound activatedSound) { + public AbilityCommonConfig(TextureAtlas.AtlasRegion icon, EffectConfig effect, PlayableSound activatedSound) { + this.icon = icon; this.effect = effect; this.activatedSound = activatedSound; } @@ -34,6 +38,7 @@ public AbilityCommonConfig(EffectConfig effect, PlayableSound activatedSound) { public static AbilityCommonConfig load(JSONObject node, EffectTypes types, GameColors cols, OggSoundManager soundManager) { EffectConfig ec = EffectConfig.load(node.has("effect") ? node.getJSONObject("effect") : null, types, cols); OggSound activatedSound = soundManager.getSound(node.getString("activatedSound")); - return new AbilityCommonConfig(ec, activatedSound); + TextureAtlas.AtlasRegion icon = node.has("icon") ? Assets.getAtlasRegion(node.getString("icon")) : null; + return new AbilityCommonConfig(icon, ec, activatedSound); } } diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java index 7a9fe8a11..10078347a 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java @@ -38,6 +38,7 @@ import org.destinationsol.game.screens.BorderDrawer; import org.destinationsol.game.screens.GameScreens; import org.destinationsol.game.screens.ZoneNameAnnouncer; +import org.destinationsol.game.ship.ShipAbility; import org.destinationsol.game.ship.SolShip; import org.destinationsol.ui.SolInputManager; import org.destinationsol.ui.UiDrawer; @@ -237,11 +238,16 @@ public Float get() { @Override public UITextureRegion get() { Hero hero = solApplication.getGame().getHero(); - if (hero.getAbility() == null) { + ShipAbility ability = hero.getAbility(); + if (ability == null) { return null; } - SolItem example = hero.getAbility().getConfig().getChargeExample(); + if (ability.getCommonConfig().icon != null) { + return Assets.getDSTexture(ability.getCommonConfig().icon.name).getUiTexture(); + } + + SolItem example = ability.getConfig().getChargeExample(); if (example != null) { return Assets.getDSTexture(example.getIcon(solApplication.getGame()).name).getUiTexture(); } diff --git a/engine/src/main/resources/org/destinationsol/assets/schemas/schemaAbilitiesConfig.json b/engine/src/main/resources/org/destinationsol/assets/schemas/schemaAbilitiesConfig.json index 6fcc9a187..63bb87746 100644 --- a/engine/src/main/resources/org/destinationsol/assets/schemas/schemaAbilitiesConfig.json +++ b/engine/src/main/resources/org/destinationsol/assets/schemas/schemaAbilitiesConfig.json @@ -11,6 +11,11 @@ "activatedSound" ], "properties": { + "icon": { + "type": "string", + "description": "The gestalt id of the icon representing this ability.", + "pattern": "^\\w+:\\w+$" + }, "activatedSound": { "type": "string", "description": "The gestalt id of the sound effect played upon ability activation.", From 36b10729b47f1c6426aa1876e43ad2d0cce97227 Mon Sep 17 00:00:00 2001 From: Benjamin Amos Date: Tue, 4 Jul 2023 22:08:52 +0100 Subject: [PATCH 04/24] doc: update README to reflect current requirements --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fe3521928..8a6ab8cc6 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Note: You can select either pure keyboard, keyboard + mouse, or controller (in t *With inventory up* * [Left, Right] - change page -* [Up, Down] - scroll up and down +* [Page Up, Page Down] - scroll up and down * [Space] - equip / unequip item *OR* buy / sell if talking to a station * [D] - discard selected item @@ -68,13 +68,13 @@ Note: You can select either pure keyboard, keyboard + mouse, or controller (in t Building and running from source -------- -You only need Java 8 installed to run Destination Sol from source. +You only need Java 11 installed to run Destination Sol from source. Run any commands in the project root directory (where you cloned / extracted the project to, using a command prompt / terminal). * Download / clone the [source from GitHub](https://github.com/MovingBlocks/DestinationSol) * To run from the command line: `gradlew run` (on Linux you might need to use `./gradlew run`) -* To prepare for IntelliJ run: `gradlew idea` then load the generated project via `DestinationSol.ipr` +* IntelliJ should import the project automatically when you open the project directory * Distributions (Windows, Linux, Mac) can be created locally by running: `gradlew distZipBundleJREs` For Android a little extra setup is needed. See instructions [here](https://github.com/MovingBlocks/DestSolAndroid). From c6ff058f6bcd64753b732dafa06ee0a67fb9caec Mon Sep 17 00:00:00 2001 From: BenjaminAmos <24301287+BenjaminAmos@users.noreply.github.com> Date: Sun, 23 Jul 2023 15:00:05 +0100 Subject: [PATCH 05/24] build: update distribution bundled JREs to Java 11 (#685) --- build-logic/src/main/groovy/destination-sol-jre.gradle | 2 +- launcher/solOSX.sh | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/build-logic/src/main/groovy/destination-sol-jre.gradle b/build-logic/src/main/groovy/destination-sol-jre.gradle index 49ccafc84..6b3328645 100644 --- a/build-logic/src/main/groovy/destination-sol-jre.gradle +++ b/build-logic/src/main/groovy/destination-sol-jre.gradle @@ -19,7 +19,7 @@ plugins { } // Uses Bellsoft Liberica JRE -def jreVersion = '8u352+8' +def jreVersion = '11.0.19+7' def jreUrlBase = "https://download.bell-sw.com/java/$jreVersion/bellsoft-jre$jreVersion" def jreUrlFilenames = [ lwjreLinux64 : 'linux-amd64.tar.gz', diff --git a/launcher/solOSX.sh b/launcher/solOSX.sh index 4e8d39fbc..20ac4887d 100755 --- a/launcher/solOSX.sh +++ b/launcher/solOSX.sh @@ -1,4 +1,2 @@ #!/usr/bin/env bash -# TODO: Target the embedded JRE again when it'll listen to arguments or otherwise find the magic trick to allow that -#lwjreOSX/bin/java -XstartOnFirstThread -jar libs/solDesktop.jar -noSplash -java -XstartOnFirstThread -jar libs/solDesktop.jar -noSplash +lwjreOSX/bin/java -XstartOnFirstThread -jar libs/solDesktop.jar -noSplash From 5d8f7bbf76b8df02c40eb421d205b6a913cd9c03 Mon Sep 17 00:00:00 2001 From: Benjamin Amos Date: Sun, 17 Sep 2023 16:11:55 +0100 Subject: [PATCH 06/24] feat: upgrade libgdx to version 1.12 --- .../src/main/groovy/destination-sol-constants.gradle | 4 ++-- .../java/org/destinationsol/ui/SolInputManager.java | 12 +++++++----- .../org/destinationsol/ui/SolInputProcessor.java | 5 +++++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/build-logic/src/main/groovy/destination-sol-constants.gradle b/build-logic/src/main/groovy/destination-sol-constants.gradle index 2e78bd425..6c1e47f38 100644 --- a/build-logic/src/main/groovy/destination-sol-constants.gradle +++ b/build-logic/src/main/groovy/destination-sol-constants.gradle @@ -3,9 +3,9 @@ ext { engineVersion = '2.1.0' gestaltVersion = '8.0.0-SNAPSHOT' - gdxVersion = '1.9.14' + gdxVersion = '1.12.0' // The LibGDX controllers library is versioned differently to the main LibGDX versions. // See https://github.com/libgdx/gdx-controllers/wiki/Compatibility for compatible versions. - gdxControllersVersion = '2.1.0' + gdxControllersVersion = '2.2.3' nuiVersion = '4.0.0-SNAPSHOT' } \ No newline at end of file diff --git a/engine/src/main/java/org/destinationsol/ui/SolInputManager.java b/engine/src/main/java/org/destinationsol/ui/SolInputManager.java index c520f8d94..0e50b0621 100644 --- a/engine/src/main/java/org/destinationsol/ui/SolInputManager.java +++ b/engine/src/main/java/org/destinationsol/ui/SolInputManager.java @@ -324,11 +324,13 @@ private void maybeFixMousePos() { int mouseX = Gdx.input.getX(); int mouseY = Gdx.input.getY(); // TODO: look into the usefulness of this, and replace with Gdx.graphics.* with displayDimensions if nothing else - int w = Gdx.graphics.getWidth(); - int h = Gdx.graphics.getHeight(); - mouseX = (int) MathUtils.clamp((float) mouseX, (float) 0, (float) w); - mouseY = (int) MathUtils.clamp((float) mouseY, (float) 0, (float) h); - Gdx.input.setCursorPosition(mouseX, mouseY); + int screenWidth = Gdx.graphics.getWidth(); + int screenHeight = Gdx.graphics.getHeight(); + if (mouseX < 0 || mouseX >= screenWidth || mouseY < 0 || mouseY >= screenHeight) { + mouseX = (int) MathUtils.clamp((float) mouseX, (float) 0, (float) screenWidth - 1); + mouseY = (int) MathUtils.clamp((float) mouseY, (float) 0, (float) screenHeight - 1); + Gdx.input.setCursorPosition(mouseX, mouseY); + } } private void updatePointers() { diff --git a/engine/src/main/java/org/destinationsol/ui/SolInputProcessor.java b/engine/src/main/java/org/destinationsol/ui/SolInputProcessor.java index 0d09036b4..d7e4079ac 100644 --- a/engine/src/main/java/org/destinationsol/ui/SolInputProcessor.java +++ b/engine/src/main/java/org/destinationsol/ui/SolInputProcessor.java @@ -59,6 +59,11 @@ public boolean touchUp(int screenX, int screenY, int pointer, int button) { return false; } + @Override + public boolean touchCancelled(int screenX, int screenY, int pointer, int button) { + return false; + } + @Override public boolean touchDragged(int screenX, int screenY, int pointer) { inputManager.maybeTouchDragged(screenX, screenY); From 3a796c03e080eeadd8b651405c0f3c2a50263bfb Mon Sep 17 00:00:00 2001 From: Benjamin Amos Date: Sun, 17 Sep 2023 17:23:14 +0100 Subject: [PATCH 07/24] build(distribution): add AArch64 macOS JRE to distribution --- .../src/main/groovy/destination-sol-jre.gradle | 3 ++- launcher/solOSX.sh | 14 +++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/build-logic/src/main/groovy/destination-sol-jre.gradle b/build-logic/src/main/groovy/destination-sol-jre.gradle index 6b3328645..502f5fa52 100644 --- a/build-logic/src/main/groovy/destination-sol-jre.gradle +++ b/build-logic/src/main/groovy/destination-sol-jre.gradle @@ -24,7 +24,8 @@ def jreUrlBase = "https://download.bell-sw.com/java/$jreVersion/bellsoft-jre$jre def jreUrlFilenames = [ lwjreLinux64 : 'linux-amd64.tar.gz', lwjre : 'windows-i586.zip', - lwjreOSX : 'macos-amd64.zip' + lwjreOSX : 'macos-amd64.zip', + lwjreOSXArm : 'macos-aarch64.zip' ] tasks.register('downloadJreAll') { diff --git a/launcher/solOSX.sh b/launcher/solOSX.sh index 20ac4887d..ac59c27e0 100755 --- a/launcher/solOSX.sh +++ b/launcher/solOSX.sh @@ -1,2 +1,14 @@ #!/usr/bin/env bash -lwjreOSX/bin/java -XstartOnFirstThread -jar libs/solDesktop.jar -noSplash + +JRE=lwjreOSX/bin/java +ARCH=$(uname -m) +if [[ "$ARCH" == "x86_64" ]]; then + JRE=lwjreOSX/bin/java +elif [[ "$ARCH" == "arm64" ]]; then + JRE=lwjreOSArm/bin/java +else + echo "Unsupported architecture $ARCH" + exit 1 +fi + +$JRE -XstartOnFirstThread -jar libs/solDesktop.jar -noSplash \ No newline at end of file From 52e65687a31115e8d5f2d3046bd1beb9bf4b3598 Mon Sep 17 00:00:00 2001 From: Benjamin Amos Date: Sun, 17 Sep 2023 21:04:35 +0100 Subject: [PATCH 08/24] fix: correct arm mac JRE path in launch script --- launcher/solOSX.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/solOSX.sh b/launcher/solOSX.sh index ac59c27e0..db68ba3ac 100755 --- a/launcher/solOSX.sh +++ b/launcher/solOSX.sh @@ -5,7 +5,7 @@ ARCH=$(uname -m) if [[ "$ARCH" == "x86_64" ]]; then JRE=lwjreOSX/bin/java elif [[ "$ARCH" == "arm64" ]]; then - JRE=lwjreOSArm/bin/java + JRE=lwjreOSXArm/bin/java else echo "Unsupported architecture $ARCH" exit 1 From 971155ffd018fa56f9429ed17f46f03595204478 Mon Sep 17 00:00:00 2001 From: BenjaminAmos <24301287+BenjaminAmos@users.noreply.github.com> Date: Sat, 28 Oct 2023 19:52:17 +0100 Subject: [PATCH 09/24] build: use new artifactory url (#692) --- .../src/main/groovy/destination-sol-repositories.gradle | 3 +-- build-logic/src/main/groovy/gestalt-repositories.gradle | 3 +-- .../src/main/groovy/terasology-publish-common.gradle | 6 ++---- build.gradle | 3 +-- engine/build.gradle | 3 +-- 5 files changed, 6 insertions(+), 12 deletions(-) diff --git a/build-logic/src/main/groovy/destination-sol-repositories.gradle b/build-logic/src/main/groovy/destination-sol-repositories.gradle index 78cedd747..416ef11c5 100644 --- a/build-logic/src/main/groovy/destination-sol-repositories.gradle +++ b/build-logic/src/main/groovy/destination-sol-repositories.gradle @@ -32,14 +32,13 @@ repositories { // Terasology Artifactory for any shared libs maven { - url "http://artifactory.terasology.org/artifactory/virtual-repo-live" + url "https://artifactory.terasology.io/artifactory/virtual-repo-live" content { includeGroupByRegex('org\\.terasology(\\..+)?') includeGroupByRegex('org\\.destinationsol(\\..+)?') // A copy of jpastebin is hosted here includeModule('brianbb', 'jpastebin') } - allowInsecureProtocol true // TODO: Review this when HTTPS finally supported. } google() diff --git a/build-logic/src/main/groovy/gestalt-repositories.gradle b/build-logic/src/main/groovy/gestalt-repositories.gradle index 06d5f94e7..327fbdfcb 100644 --- a/build-logic/src/main/groovy/gestalt-repositories.gradle +++ b/build-logic/src/main/groovy/gestalt-repositories.gradle @@ -15,12 +15,11 @@ repositories { // Terasology Artifactory for any shared libs maven { - url "http://artifactory.terasology.org/artifactory/virtual-repo-live" + url "https://artifactory.terasology.io/artifactory/virtual-repo-live" content { includeGroupByRegex('org\\.terasology.gestalt(\\..+)?') // A copy of Java-semver is hosted here too includeModule('com.github.zafarkhaja', 'java-semver') } - allowInsecureProtocol true // TODO: Review this when HTTPS finally supported. } } \ No newline at end of file diff --git a/build-logic/src/main/groovy/terasology-publish-common.gradle b/build-logic/src/main/groovy/terasology-publish-common.gradle index 405558ded..2c0c8c1eb 100644 --- a/build-logic/src/main/groovy/terasology-publish-common.gradle +++ b/build-logic/src/main/groovy/terasology-publish-common.gradle @@ -15,11 +15,9 @@ publishing { repositories { maven { name = 'TerasologyOrg' - allowInsecureProtocol true // Still no HTTPS on our Artifactory yet... - if (rootProject.hasProperty("publishRepo")) { // This first option is good for local testing, you can set a full explicit target repo in gradle.properties - url = "http://artifactory.terasology.org/artifactory/$publishRepo" + url = "https://artifactory.terasology.io/artifactory/$publishRepo" logger.info("Changing PUBLISH repoKey set via Gradle property to {}", publishRepo) } else { @@ -38,7 +36,7 @@ publishing { } logger.info("The final deduced publish repo is {}", deducedPublishRepo) - url = "http://artifactory.terasology.org/artifactory/$deducedPublishRepo" + url = "https://artifactory.terasology.io/artifactory/$deducedPublishRepo" } if (rootProject.hasProperty("mavenUser") && rootProject.hasProperty("mavenPass")) { diff --git a/build.gradle b/build.gradle index 2503ef49f..aab26bd80 100644 --- a/build.gradle +++ b/build.gradle @@ -18,8 +18,7 @@ repositories { // Terasology Artifactory for any shared libs maven { - url "http://artifactory.terasology.org/artifactory/virtual-repo-live" - allowInsecureProtocol true // TODO: Review this when HTTPS finally supported. + url "https://artifactory.terasology.io/artifactory/virtual-repo-live" } maven { url "https://maven.google.com" } diff --git a/engine/build.gradle b/engine/build.gradle index 216af6515..e54bf0991 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -21,8 +21,7 @@ buildscript { google() maven { - url "http://artifactory.terasology.org/artifactory/virtual-repo-live" - allowInsecureProtocol true // TODO: Review this when HTTPS finally supported. + url "https://artifactory.terasology.io/artifactory/virtual-repo-live" } // Needed for Jsemver, which is a gestalt dependency maven { url = 'https://heisluft.de/maven/' } From 0263edf91d32f00fead8ae7ca2e660c098a9ce18 Mon Sep 17 00:00:00 2001 From: BenjaminAmos <24301287+BenjaminAmos@users.noreply.github.com> Date: Sun, 5 Nov 2023 16:40:53 +0000 Subject: [PATCH 10/24] fix: fix tutorial crash when waypoint removed (#691) --- .../game/tutorial/TutorialManager.java | 2 +- .../steps/FlyToHeroFirstWaypointStep.java | 21 ++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/engine/src/main/java/org/destinationsol/game/tutorial/TutorialManager.java b/engine/src/main/java/org/destinationsol/game/tutorial/TutorialManager.java index 488f5f362..a826ed6a9 100644 --- a/engine/src/main/java/org/destinationsol/game/tutorial/TutorialManager.java +++ b/engine/src/main/java/org/destinationsol/game/tutorial/TutorialManager.java @@ -228,7 +228,7 @@ public void start() { solGame.get().getScreens().mapScreen.getCloseButton(), solGame.get().getScreens().mapScreen, "Close the map."), - new FlyToHeroFirstWaypointStep("Fly to your waypoint."), + new FlyToHeroFirstWaypointStep("Fly to your waypoint.", "Create a waypoint near your ship."), new ChangeTutorialSectionStep("Planets"), new FlyToPlanetSellingMercenariesStep("Head towards a planet.", "Look for the planetary station."), new ChangeTutorialSectionStep("Mercenaries"), diff --git a/engine/src/main/java/org/destinationsol/game/tutorial/steps/FlyToHeroFirstWaypointStep.java b/engine/src/main/java/org/destinationsol/game/tutorial/steps/FlyToHeroFirstWaypointStep.java index f218c9b0a..1a2f00292 100644 --- a/engine/src/main/java/org/destinationsol/game/tutorial/steps/FlyToHeroFirstWaypointStep.java +++ b/engine/src/main/java/org/destinationsol/game/tutorial/steps/FlyToHeroFirstWaypointStep.java @@ -25,24 +25,39 @@ * A tutorial step that completes when the player ship reaches a nearby spawned waypoint. */ public class FlyToHeroFirstWaypointStep extends FlyToWaypointStep { + private final String missingWaypointMessage; + @Inject protected FlyToHeroFirstWaypointStep() { throw new RuntimeException("Attempted to instantiate TutorialStep via DI. This is not supported."); } - public FlyToHeroFirstWaypointStep(String message) { + public FlyToHeroFirstWaypointStep(String message, String missingWaypointMessage) { super(Vector2.Zero, message); + this.missingWaypointMessage = missingWaypointMessage; } @Override public void start() { - waypoint = game.getHero().getWaypoints().get(0); - setTutorialText(message); + Hero hero = game.getHero(); + if (hero.getWaypoints().isEmpty()) { + setTutorialText(missingWaypointMessage); + } else { + waypoint = game.getHero().getWaypoints().get(0); + setTutorialText(message); + } } @Override public boolean checkComplete(float timeStep) { Hero hero = game.getHero(); + if (hero.getWaypoints().isEmpty()) { + setTutorialText(missingWaypointMessage); + return false; + } else { + setTutorialText(message); + } + if (!hero.getWaypoints().contains(waypoint) && hero.getWaypoints().size() > 0) { // Change the target waypoint just in-case the player removes it. waypoint = hero.getWaypoints().get(0); From 98cb33c73605af13c8cb42f39a5d0119fd24af65 Mon Sep 17 00:00:00 2001 From: Benjamin Amos Date: Sun, 3 Dec 2023 17:40:13 +0000 Subject: [PATCH 11/24] feat: upgrade libgdx to version 1.12.1 --- build-logic/src/main/groovy/destination-sol-constants.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-logic/src/main/groovy/destination-sol-constants.gradle b/build-logic/src/main/groovy/destination-sol-constants.gradle index 6c1e47f38..bfb515634 100644 --- a/build-logic/src/main/groovy/destination-sol-constants.gradle +++ b/build-logic/src/main/groovy/destination-sol-constants.gradle @@ -3,7 +3,7 @@ ext { engineVersion = '2.1.0' gestaltVersion = '8.0.0-SNAPSHOT' - gdxVersion = '1.12.0' + gdxVersion = '1.12.1' // The LibGDX controllers library is versioned differently to the main LibGDX versions. // See https://github.com/libgdx/gdx-controllers/wiki/Compatibility for compatible versions. gdxControllersVersion = '2.2.3' From 397ec4bc100b1c7d7cda43fd9c1d644bda3f0e4f Mon Sep 17 00:00:00 2001 From: Benjamin Amos Date: Sun, 3 Dec 2023 17:46:50 +0000 Subject: [PATCH 12/24] fix(ui): fix UI rendering on scaled high-DPI displays --- engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java b/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java index f0e93e2af..922379545 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/NUIManager.java @@ -169,7 +169,7 @@ public NUIManager(SolApplication solApplication, UIText.DEFAULT_CURSOR_TEXTURE = whiteTexture; // NOTE: SolApplication::addResizeSubscriber is not intended to be static, so use the instance form for compatibility - solApplication.addResizeSubscriber(() -> resize(Gdx.graphics.getBackBufferWidth(), Gdx.graphics.getBackBufferHeight())); + solApplication.addResizeSubscriber(() -> resize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight())); // Mobile screen densities can vary considerably, so a large digital resolution can be displayed // on a very small screen. Due to this, it makes sense to scale the UI roughly proportionally From 1501eb5d5a8f0b6196930b1300f5df4742282ea7 Mon Sep 17 00:00:00 2001 From: Du4lity5151 Date: Tue, 24 Dec 2024 02:46:01 -0800 Subject: [PATCH 13/24] Ship engine parameters are editable (#702) "rotationAcceleration", "acceleration", and "maxRotationSpeed" have been changed from constants/conditional constants to editable engine parameters that can be set in engine JSON files. If not specified, it uses default values. This is useful for changing the way ships turn or accelerate. --- .../src/main/java/org/destinationsol/game/item/Engine.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/src/main/java/org/destinationsol/game/item/Engine.java b/engine/src/main/java/org/destinationsol/game/item/Engine.java index 4af344e1d..4368a2cd1 100644 --- a/engine/src/main/java/org/destinationsol/game/item/Engine.java +++ b/engine/src/main/java/org/destinationsol/game/item/Engine.java @@ -123,9 +123,9 @@ public static Config load(String engineName) { JSONObject rootNode = Validator.getValidatedJSON(engineName, "engine:schemaEngine"); boolean isBig = rootNode.getBoolean("big"); - float rotationAcceleration = isBig ? 100f : 515f; - float acceleration = 2f; - float maxRotationSpeed = isBig ? 40f : 230f; + float rotationAcceleration = (float) rootNode.optDouble("rotationAcceleration", isBig ? 100f : 515f); + float acceleration = (float) rootNode.optDouble("acceleration", 2f); + float maxRotationSpeed = (float) rootNode.optDouble("maxRotationSpeed", isBig ? 40f : 230f); // TODO: VAMPCAT: The icon / displayName was initially set to null. Is that correct? From 5a30d273b2670be70a6f1c7c1465154a88138463 Mon Sep 17 00:00:00 2001 From: Cervator Date: Wed, 25 Dec 2024 23:28:25 -0500 Subject: [PATCH 14/24] build: different way to trigger Android config --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index f1defaf60..3adb2fe66 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -33,7 +33,7 @@ pipeline { } stage('Build Android') { steps { - sh 'echo sdk.dir=/opt/android-sdk > local.properties' + writeFile file: 'local.properties', text: 'sdk.dir=/opt/android-sdk' dir('android') { script { // Allow varying from the default Android repo path for easier development. Assume same Android branch as engine branch. From acc527f5d10cefe10e9f782a18fc252d7089c702 Mon Sep 17 00:00:00 2001 From: Cervator Date: Thu, 26 Dec 2024 00:37:19 -0500 Subject: [PATCH 15/24] Debugging --- Jenkinsfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 3adb2fe66..3e5af84d0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -34,6 +34,9 @@ pipeline { stage('Build Android') { steps { writeFile file: 'local.properties', text: 'sdk.dir=/opt/android-sdk' + sh 'pwd' + sh 'ls -la' + sh 'cat local.properties' dir('android') { script { // Allow varying from the default Android repo path for easier development. Assume same Android branch as engine branch. From aab6c533560611e4e5717b9cd78eecbc67f00380 Mon Sep 17 00:00:00 2001 From: Cervator Date: Thu, 26 Dec 2024 01:05:03 -0500 Subject: [PATCH 16/24] More debugging --- Jenkinsfile | 60 +++++++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 3e5af84d0..1f0892237 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -33,36 +33,42 @@ pipeline { } stage('Build Android') { steps { - writeFile file: 'local.properties', text: 'sdk.dir=/opt/android-sdk' - sh 'pwd' - sh 'ls -la' - sh 'cat local.properties' - dir('android') { - script { - // Allow varying from the default Android repo path for easier development. Assume same Android branch as engine branch. - def androidGitPath = "https://github.com/MovingBlocks/DestSolAndroid.git" - if (env.PUBLISH_ORG) { - androidGitPath = androidGitPath.replace("MovingBlocks", env.PUBLISH_ORG) - println "Updated target Android Git path to: " + androidGitPath - } else { - println "Not varying the Android path from default " + androidGitPath - } - // Figure out a suitable target branch in the Android repo, default is the develop branch - def androidBranch = "develop" - // Check to see if Jenkins is building a tag, branch, or other (including PRs) - if (env.TAG_NAME != null && env.TAG_NAME ==~ /v\d+\.\d+\.\d+.*/) { - println "Going to use target Android tag " + env.TAG_NAME - androidBranch = "refs/tags/" + env.TAG_NAME - } else if (env.BRANCH_NAME.equalsIgnoreCase("master") || env.BRANCH_NAME.startsWith("android/")) { - println "Going to use target unusual Android branch " + env.BRANCH_NAME - androidBranch = env.BRANCH_NAME - } else { - println "Going to use target Android branch 'develop' - not building 'master' nor anything starting with 'android/'" + // Set the ANDROID_HOME environment variable + withEnv(['ANDROID_HOME=/opt/android-sdk']) { + + writeFile file: 'local.properties', text: 'sdk.dir=/opt/android-sdk' + + sh 'echo "ANDROID_HOME is: $ANDROID_HOME"' + sh 'pwd' + sh 'ls -la' + sh 'cat local.properties' + dir('android') { + script { + // Allow varying from the default Android repo path for easier development. Assume same Android branch as engine branch. + def androidGitPath = "https://github.com/MovingBlocks/DestSolAndroid.git" + if (env.PUBLISH_ORG) { + androidGitPath = androidGitPath.replace("MovingBlocks", env.PUBLISH_ORG) + println "Updated target Android Git path to: " + androidGitPath + } else { + println "Not varying the Android path from default " + androidGitPath + } + // Figure out a suitable target branch in the Android repo, default is the develop branch + def androidBranch = "develop" + // Check to see if Jenkins is building a tag, branch, or other (including PRs) + if (env.TAG_NAME != null && env.TAG_NAME ==~ /v\d+\.\d+\.\d+.*/) { + println "Going to use target Android tag " + env.TAG_NAME + androidBranch = "refs/tags/" + env.TAG_NAME + } else if (env.BRANCH_NAME.equalsIgnoreCase("master") || env.BRANCH_NAME.startsWith("android/")) { + println "Going to use target unusual Android branch " + env.BRANCH_NAME + androidBranch = env.BRANCH_NAME + } else { + println "Going to use target Android branch 'develop' - not building 'master' nor anything starting with 'android/'" + } + checkout scm: [$class: 'GitSCM', branches: [[name: androidBranch]], extensions: [], userRemoteConfigs: [[credentialsId: 'GooeyHub', url: androidGitPath]]] } - checkout scm: [$class: 'GitSCM', branches: [[name: androidBranch]], extensions: [], userRemoteConfigs: [[credentialsId: 'GooeyHub', url: androidGitPath]]] } + sh './gradlew :android:assembleDebug' } - sh './gradlew :android:assembleDebug' archiveArtifacts 'android/build/outputs/apk/debug/android-debug.apk' } } From bc3700c71f60368d29da36aa975a974e81bf5a18 Mon Sep 17 00:00:00 2001 From: Cervator Date: Fri, 27 Dec 2024 00:03:46 -0500 Subject: [PATCH 17/24] Target specific container --- Jenkinsfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 1f0892237..393ce7e0c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,6 +1,9 @@ pipeline { agent { - label 'android' + kubernetes { + label 'android' + defaultContainer 'builder' // Use actual container with Android SDK present + } } stages { stage('Setup') { From f83e8209d67af23c98782a32b6b5d215bab1e94b Mon Sep 17 00:00:00 2001 From: BenjaminAmos <24301287+BenjaminAmos@users.noreply.github.com> Date: Tue, 31 Dec 2024 13:13:13 +0000 Subject: [PATCH 18/24] Module select UI (#662) --- .../org/destinationsol/SolApplication.java | 3 + .../destinationsol/assets/AssetHelper.java | 4 + .../assets/music/OggMusicManager.java | 2 +- .../org/destinationsol/game/SaveManager.java | 32 +++++ .../org/destinationsol/game/WorldConfig.java | 17 ++- .../game/console/ConsoleImpl.java | 2 +- .../org/destinationsol/menu/MenuScreens.java | 3 + .../destinationsol/modules/ModuleManager.java | 18 ++- .../nui/screens/mainMenu/MainMenuScreen.java | 10 +- .../nui/screens/mainMenu/ModulesScreen.java | 109 ++++++++++++++++++ .../nui/screens/mainMenu/NewShipScreen.java | 56 +++++++-- .../destinationsol/assets/skins/mainMenu.skin | 3 + .../assets/ui/mainMenu/modulesScreen.ui | 106 +++++++++++++++++ .../assets/ui/mainMenu/newShipScreen.ui | 12 ++ 14 files changed, 361 insertions(+), 16 deletions(-) create mode 100644 engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/ModulesScreen.java create mode 100644 engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/modulesScreen.ui diff --git a/engine/src/main/java/org/destinationsol/SolApplication.java b/engine/src/main/java/org/destinationsol/SolApplication.java index 8cd6a54ba..50b9f58e4 100644 --- a/engine/src/main/java/org/destinationsol/SolApplication.java +++ b/engine/src/main/java/org/destinationsol/SolApplication.java @@ -333,6 +333,9 @@ private void draw() { public void play(boolean tut, String shipName, boolean isNewGame, WorldConfig worldConfig) { ModuleManager moduleManager = appContext.getBean(ModuleManager.class); + moduleManager.loadEnvironment(worldConfig.getModules()); + appContext.getBean(AssetHelper.class).switchEnvironment(moduleManager.getEnvironment()); + gameContext = appContext.getNestedContainer( new GameConfigurationServiceRegistry(worldConfig), new EventReceiverServiceRegistry(moduleManager.getEnvironment()), diff --git a/engine/src/main/java/org/destinationsol/assets/AssetHelper.java b/engine/src/main/java/org/destinationsol/assets/AssetHelper.java index c9cdb2c9d..79af1120d 100644 --- a/engine/src/main/java/org/destinationsol/assets/AssetHelper.java +++ b/engine/src/main/java/org/destinationsol/assets/AssetHelper.java @@ -131,6 +131,10 @@ public Set listAssets(Class> type, String asset, return list; } + public void switchEnvironment(ModuleEnvironment environment) { + assetTypeManager.switchEnvironment(environment); + } + public void dispose() { try { assetTypeManager.unloadEnvironment(); diff --git a/engine/src/main/java/org/destinationsol/assets/music/OggMusicManager.java b/engine/src/main/java/org/destinationsol/assets/music/OggMusicManager.java index c4c3619fb..cf7ff2b72 100644 --- a/engine/src/main/java/org/destinationsol/assets/music/OggMusicManager.java +++ b/engine/src/main/java/org/destinationsol/assets/music/OggMusicManager.java @@ -238,7 +238,7 @@ public void unregisterModuleMusic() { } public void resetMusic() { - musicMap.put(GAME_MUSIC_SET, new ArrayList<>()); + musicMap.clear(); } public String getCurrentMusicSet() { diff --git a/engine/src/main/java/org/destinationsol/game/SaveManager.java b/engine/src/main/java/org/destinationsol/game/SaveManager.java index cc4725006..b12359e32 100644 --- a/engine/src/main/java/org/destinationsol/game/SaveManager.java +++ b/engine/src/main/java/org/destinationsol/game/SaveManager.java @@ -36,10 +36,13 @@ import org.destinationsol.game.item.SolItem; import org.destinationsol.game.ship.SolShip; import org.destinationsol.game.ship.hulls.HullConfig; +import org.destinationsol.modules.ModuleManager; import org.destinationsol.ui.Waypoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.context.annotation.API; +import org.terasology.gestalt.module.Module; +import org.terasology.gestalt.naming.Name; import java.io.File; import java.io.FileNotFoundException; @@ -50,8 +53,10 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Optional; +import java.util.Set; @API public class SaveManager { @@ -263,6 +268,15 @@ public static void saveWorld(WorldConfig worldConfig) { } world.add("featureGenerators", featureGenerators); + JsonArray modulesArray = new JsonArray(); + for (Name module : ModuleManager.getEnvironmentStatic().getModuleIdsOrderedByDependencies()) { + // Exclude built-in modules + if (module.compareTo("engine") != 0 && module.compareTo("nui") != 0) { + modulesArray.add(module.toString()); + } + } + world.add("modules", modulesArray); + Gson gson = new GsonBuilder().setPrettyPrinting().create(); String stringToWrite = gson.toJson(world); @@ -316,6 +330,24 @@ public static Optional loadWorld() { config.setFeatureGenerators(featureGenerators); } + if (world.has("modules")) { + Set modules = new HashSet<>(); + for (JsonElement value : world.getAsJsonArray("modules")) { + if (value.isJsonPrimitive() && value.getAsJsonPrimitive().isString()) { + Module module = ModuleManager.getEnvironmentStatic().get(new Name(value.getAsString())); + if (module != null) { + modules.add(module); + } else { + logger.warn("The module \"" + value.getAsString() + "\" is missing!"); + } + } + } + config.setModules(modules); + } else { + // This is for compatibility with older saves, which always used all modules unconditionally. + config.setModules(new HashSet<>(ModuleManager.getEnvironmentStatic().getModulesOrderedByDependencies())); + } + logger.debug("Successfully loaded the world file"); return Optional.of(config); } catch (FileNotFoundException e) { diff --git a/engine/src/main/java/org/destinationsol/game/WorldConfig.java b/engine/src/main/java/org/destinationsol/game/WorldConfig.java index fcb636b44..23f077992 100644 --- a/engine/src/main/java/org/destinationsol/game/WorldConfig.java +++ b/engine/src/main/java/org/destinationsol/game/WorldConfig.java @@ -16,30 +16,37 @@ package org.destinationsol.game; import org.destinationsol.game.planet.SystemsBuilder; +import org.terasology.gestalt.module.Module; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; public class WorldConfig { protected long seed; protected int numberOfSystems; private List solarSystemGenerators; private List featureGenerators; + private Set modules; public WorldConfig() { seed = System.currentTimeMillis(); numberOfSystems = SystemsBuilder.DEFAULT_SYSTEM_COUNT; solarSystemGenerators = new ArrayList<>(); featureGenerators = new ArrayList<>(); + modules = new HashSet<>(); } public WorldConfig(long seed, int numberOfSystems, List solarSystemGenerators, - List featureGenerators) { + List featureGenerators, + Set modules) { this.seed = seed; this.numberOfSystems = numberOfSystems; this.solarSystemGenerators = solarSystemGenerators; this.featureGenerators = featureGenerators; + this.modules = modules; } public long getSeed() { @@ -73,4 +80,12 @@ public List getFeatureGenerators() { public void setSolarSystemGenerators(List solarSystemGenerators) { this.solarSystemGenerators = solarSystemGenerators; } + + public Set getModules() { + return modules; + } + + public void setModules(Set modules) { + this.modules = modules; + } } diff --git a/engine/src/main/java/org/destinationsol/game/console/ConsoleImpl.java b/engine/src/main/java/org/destinationsol/game/console/ConsoleImpl.java index 9d79a7e6f..133127e8d 100644 --- a/engine/src/main/java/org/destinationsol/game/console/ConsoleImpl.java +++ b/engine/src/main/java/org/destinationsol/game/console/ConsoleImpl.java @@ -89,7 +89,7 @@ private static List splitParameters(String paramStr) { } public void init(SolGame game) { - + commandRegistry.clear(); for (Class commands : context.get(ModuleManager.class).getEnvironment().getTypesAnnotatedWith(RegisterCommands.class)) { try { Object commandsObject = commands.newInstance(); diff --git a/engine/src/main/java/org/destinationsol/menu/MenuScreens.java b/engine/src/main/java/org/destinationsol/menu/MenuScreens.java index 38ac08815..5d7c5e92c 100644 --- a/engine/src/main/java/org/destinationsol/menu/MenuScreens.java +++ b/engine/src/main/java/org/destinationsol/menu/MenuScreens.java @@ -22,6 +22,7 @@ import org.destinationsol.ui.nui.screens.mainMenu.InputMapScreen; import org.destinationsol.ui.nui.screens.mainMenu.LoadingScreen; import org.destinationsol.ui.nui.screens.mainMenu.MainMenuScreen; +import org.destinationsol.ui.nui.screens.mainMenu.ModulesScreen; import org.destinationsol.ui.nui.screens.mainMenu.NewGameScreen; import org.destinationsol.ui.nui.screens.mainMenu.NewShipScreen; import org.destinationsol.ui.nui.screens.mainMenu.OptionsScreen; @@ -36,6 +37,7 @@ public class MenuScreens { public final LoadingScreen loading; public final NewGameScreen newGame; public final NewShipScreen newShip; + public final ModulesScreen modules; public MenuScreens(SolLayouts layouts, boolean mobile, GameOptions gameOptions, NUIManager nuiManager) { MenuLayout menuLayout = layouts.menuLayout; @@ -47,5 +49,6 @@ public MenuScreens(SolLayouts layouts, boolean mobile, GameOptions gameOptions, loading = (LoadingScreen) nuiManager.createScreen("engine:loadingScreen"); newGame = (NewGameScreen) nuiManager.createScreen("engine:newGameScreen"); newShip = (NewShipScreen) nuiManager.createScreen("engine:newShipScreen"); + modules = (ModulesScreen) nuiManager.createScreen("engine:modulesScreen"); } } diff --git a/engine/src/main/java/org/destinationsol/modules/ModuleManager.java b/engine/src/main/java/org/destinationsol/modules/ModuleManager.java index fad354ab0..741c770e4 100644 --- a/engine/src/main/java/org/destinationsol/modules/ModuleManager.java +++ b/engine/src/main/java/org/destinationsol/modules/ModuleManager.java @@ -220,6 +220,7 @@ public class ModuleManager implements AutoCloseable { private final FacadeModuleConfig moduleConfig; protected ModuleRegistry registry; protected Module engineModule; + private Set builtInModules; @Inject public ModuleManager(BeanContext beanContext, ModuleFactory moduleFactory, ModuleRegistry moduleRegistry, @@ -240,9 +241,12 @@ public void init() throws Exception { File modulesRoot = moduleConfig.getModulesPath(); scanner.scan(registry, modulesRoot); + builtInModules = Sets.newHashSet(); + builtInModules.add(engineModule); + builtInModules.add(nuiModule); + registry.addAll(builtInModules); + Set requiredModules = Sets.newHashSet(); - registry.add(engineModule); - registry.add(nuiModule); requiredModules.addAll(registry); loadEnvironment(requiredModules); @@ -253,6 +257,8 @@ public void init() throws Exception { } public void loadEnvironment(Set modules) { + modules.addAll(builtInModules); + StandardPermissionProviderFactory permissionFactory = new StandardPermissionProviderFactory(); for (String api : API_WHITELIST) { permissionFactory.getBasePermissionSet().addAPIPackage(api); @@ -288,6 +294,10 @@ public ModuleEnvironment getEnvironment() { return environment; } + public Set getBuiltInModules() { + return builtInModules; + } + //TODO: REMOVE THIS public static ModuleEnvironment getEnvironmentStatic() { return environment; @@ -299,6 +309,10 @@ public void printAvailableModules() { } } + public ModuleRegistry getRegistry() { + return registry; + } + public void dispose() { environment.close(); } diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/MainMenuScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/MainMenuScreen.java index 34ecb7759..d72e13293 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/MainMenuScreen.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/MainMenuScreen.java @@ -20,12 +20,14 @@ import org.destinationsol.SolApplication; import org.destinationsol.assets.music.OggMusicManager; import org.destinationsol.game.WorldConfig; +import org.destinationsol.modules.ModuleManager; import org.destinationsol.ui.nui.NUIManager; import org.destinationsol.ui.nui.NUIScreenLayer; import org.terasology.nui.Canvas; import org.terasology.nui.widgets.UIButton; import javax.inject.Inject; +import java.util.HashSet; /** * The main menu screen. This is the first screen shown when you open the game. @@ -33,18 +35,22 @@ public class MainMenuScreen extends NUIScreenLayer { private final SolApplication solApplication; + private final ModuleManager moduleManager; private UIButton tutorialButton; @Inject - public MainMenuScreen(SolApplication solApplication) { + public MainMenuScreen(SolApplication solApplication, ModuleManager moduleManager) { this.solApplication = solApplication; + this.moduleManager = moduleManager; } @Override public void initialise() { tutorialButton = find("tutorialButton", UIButton.class); tutorialButton.subscribe(button -> { - solApplication.getMenuScreens().loading.setMode(true, "Imperial Small", true, new WorldConfig()); + WorldConfig worldConfig = new WorldConfig(); + worldConfig.setModules(new HashSet<>(moduleManager.getEnvironment().getModulesOrderedByDependencies())); + solApplication.getMenuScreens().loading.setMode(true, "Imperial Small", true, worldConfig); nuiManager.setScreen(solApplication.getMenuScreens().loading); }); diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/ModulesScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/ModulesScreen.java new file mode 100644 index 000000000..7c0119f04 --- /dev/null +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/ModulesScreen.java @@ -0,0 +1,109 @@ +/* + * Copyright 2022 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.destinationsol.ui.nui.screens.mainMenu; + +import org.destinationsol.SolApplication; +import org.destinationsol.modules.ModuleManager; +import org.destinationsol.ui.nui.NUIScreenLayer; +import org.terasology.gestalt.module.Module; +import org.terasology.nui.databinding.ReadOnlyBinding; +import org.terasology.nui.itemRendering.StringTextRenderer; +import org.terasology.nui.widgets.UIButton; +import org.terasology.nui.widgets.UIList; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * This screen is used to select the modules that should be active when playing a particular save. + * You can activate and de-activate modules only when initially creating a game. + * This is to prevent side-effects from new modules being introduced unexpectedly. + */ +public class ModulesScreen extends NUIScreenLayer { + private final SolApplication solApplication; + private final ModuleManager moduleManager; + private Set selectedModules; + + @Inject + public ModulesScreen(SolApplication solApplication, ModuleManager moduleManager) { + this.solApplication = solApplication; + this.moduleManager = moduleManager; + } + + @Override + public void initialise() { + selectedModules = new HashSet<>(); + + UIList moduleList = find("modulesList", UIList.class); + List modules = new ArrayList<>(moduleManager.getEnvironment().getModulesOrderedByDependencies()); + modules.removeAll(moduleManager.getBuiltInModules()); + moduleList.setList(modules); + moduleList.setItemRenderer(new StringTextRenderer() { + @Override + public String getString(Module value) { + if (!selectedModules.contains(value)) { + return value.getId().toString(); + } else { + return value.getId().toString() + " (Active)"; + } + } + }); + moduleList.subscribe((list, module) -> { + if (selectedModules.contains(module)) { + selectedModules.remove(module); + } else { + selectedModules.add(module); + } + }); + + UIButton activateButton = find("activateButton", UIButton.class); + activateButton.bindEnabled(new ReadOnlyBinding() { + @Override + public Boolean get() { + Module selectedModule = moduleList.getSelection(); + return selectedModule != null && !selectedModules.contains(selectedModule); + } + }); + activateButton.subscribe(button -> selectedModules.add(moduleList.getSelection())); + + UIButton deactivateButton = find("deactivateButton", UIButton.class); + deactivateButton.bindEnabled(new ReadOnlyBinding() { + @Override + public Boolean get() { + Module selectedModule = moduleList.getSelection(); + return selectedModule != null && selectedModules.contains(selectedModule); + } + }); + deactivateButton.subscribe(button -> selectedModules.remove(moduleList.getSelection())); + + UIButton confirmButton = find("confirmButton", UIButton.class); + confirmButton.subscribe(button -> { + nuiManager.setScreen(solApplication.getMenuScreens().newShip); + }); + } + + public Set getSelectedModules() { + return selectedModules; + } + + public void setSelectedModules(Set selectedModules) { + this.selectedModules = selectedModules; + } +} diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/NewShipScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/NewShipScreen.java index a9d0e1b6c..d2b6dcdc4 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/NewShipScreen.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/mainMenu/NewShipScreen.java @@ -21,6 +21,7 @@ import org.destinationsol.assets.json.Validator; import org.destinationsol.game.WorldConfig; import org.destinationsol.game.planet.SystemsBuilder; +import org.destinationsol.modules.ModuleManager; import org.destinationsol.ui.nui.NUIManager; import org.destinationsol.ui.nui.NUIScreenLayer; import org.destinationsol.ui.nui.widgets.KeyActivatedButton; @@ -28,6 +29,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.gestalt.assets.ResourceUrn; +import org.terasology.gestalt.module.Module; +import org.terasology.gestalt.naming.Name; import org.terasology.nui.Canvas; import org.terasology.nui.UITextureRegion; import org.terasology.nui.backends.libgdx.GDXInputUtil; @@ -36,32 +39,41 @@ import javax.inject.Inject; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Optional; +import java.util.Set; public class NewShipScreen extends NUIScreenLayer { private static final Logger logger = LoggerFactory.getLogger(NewShipScreen.class); private final SolApplication solApplication; - private int numberOfSystems = SystemsBuilder.DEFAULT_SYSTEM_COUNT; + private final ModuleManager moduleManager; private int playerSpawnConfigIndex = 0; private List playerSpawnConfigNames = new ArrayList<>(); private List playerSpawnConfigTextures = new ArrayList<>(); + private WorldConfig worldConfig; @Inject - public NewShipScreen(SolApplication solApplication) { + public NewShipScreen(SolApplication solApplication, ModuleManager moduleManager) { this.solApplication = solApplication; + this.moduleManager = moduleManager; } @Override public void initialise() { + worldConfig = new WorldConfig(); + worldConfig.setNumberOfSystems(SystemsBuilder.DEFAULT_SYSTEM_COUNT); + worldConfig.setModules(new HashSet<>(moduleManager.getEnvironment().getModulesOrderedByDependencies())); + UIButton systemsButton = find("systemsButton", UIButton.class); - systemsButton.setText("Systems: " + numberOfSystems); + systemsButton.setText("Systems: " + worldConfig.getNumberOfSystems()); systemsButton.subscribe(button -> { - int systemCount = (numberOfSystems + 1) % 10; + int systemCount = (worldConfig.getNumberOfSystems() + 1) % 10; if (systemCount < 2) { systemCount = 2; } - numberOfSystems = systemCount; - ((UIButton)button).setText("Systems: " + numberOfSystems); + worldConfig.setNumberOfSystems(systemCount); + ((UIButton)button).setText("Systems: " + worldConfig.getNumberOfSystems()); }); for (ResourceUrn configUrn : Assets.getAssetHelper().listAssets(Json.class, "playerSpawnConfig")) { @@ -90,13 +102,17 @@ public void initialise() { shipPreviewImage.setImage(playerSpawnConfigTextures.get(playerSpawnConfigIndex)); }); + UIButton modulesButton = find("modulesButton", UIButton.class); + modulesButton.subscribe(button -> { + ModulesScreen modulesScreen = solApplication.getMenuScreens().modules; + modulesScreen.setSelectedModules(worldConfig.getModules()); + nuiManager.setScreen(modulesScreen); + }); + // NOTE: The original code used getKeyEscape() for both the "OK" and "Cancel" buttons. This was probably a mistake. KeyActivatedButton okButton = find("okButton", KeyActivatedButton.class); okButton.setKey(GDXInputUtil.GDXToNuiKey(solApplication.getOptions().getKeyShoot())); okButton.subscribe(button -> { - WorldConfig worldConfig = new WorldConfig(); - worldConfig.setNumberOfSystems(numberOfSystems); - LoadingScreen loadingScreen = solApplication.getMenuScreens().loading; loadingScreen.setMode(false, playerSpawnConfigNames.get(playerSpawnConfigIndex), true, worldConfig); nuiManager.setScreen(loadingScreen); @@ -109,6 +125,28 @@ public void initialise() { }); } + @Override + public void onAdded() { + worldConfig.setSeed(System.currentTimeMillis()); + + String currentShip = playerSpawnConfigNames.get(playerSpawnConfigIndex); + playerSpawnConfigNames.clear(); + Set configUrns = Assets.getAssetHelper().listAssets(Json.class, "playerSpawnConfig"); + for (Module module : worldConfig.getModules()) { + ResourceUrn configUrn = new ResourceUrn(module.getId(), new Name("playerSpawnConfig")); + if (configUrns.contains(configUrn)) { + playerSpawnConfigNames.addAll(Validator.getValidatedJSON(configUrn.toString(), "engine:schemaPlayerSpawnConfig").keySet()); + } + } + + if (!playerSpawnConfigNames.contains(currentShip)) { + // The player picked a ship that's now invalid, so reset their selection. + playerSpawnConfigIndex = 0; + UIButton startingShipButton = find("startingShipButton", UIButton.class); + startingShipButton.setText("Starting Ship: " + playerSpawnConfigNames.get(playerSpawnConfigIndex)); + } + } + @Override public void update(float delta) { super.update(delta); diff --git a/engine/src/main/resources/org/destinationsol/assets/skins/mainMenu.skin b/engine/src/main/resources/org/destinationsol/assets/skins/mainMenu.skin index 685ba8726..bcb6b5703 100644 --- a/engine/src/main/resources/org/destinationsol/assets/skins/mainMenu.skin +++ b/engine/src/main/resources/org/destinationsol/assets/skins/mainMenu.skin @@ -61,6 +61,9 @@ "creditsButton": { "font": "engine:main#0.60" }, + "modulesButton": { + "font": "engine:main#0.55" + }, "menuHeaderText": { "font": "engine:main#1.0" }, diff --git a/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/modulesScreen.ui b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/modulesScreen.ui new file mode 100644 index 000000000..ff3ef21bf --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/modulesScreen.ui @@ -0,0 +1,106 @@ +{ + "type": "ModulesScreen", + "skin": "engine:mainMenu", + "contents": { + "type": "RelativeLayout", + "contents": [ + { + "type": "UILabel", + "id": "headerText", + "family": "menuHeaderText", + "text": "Modules", + "layoutInfo": { + "position-horizontal-center": {}, + "position-top": { + "target": "TOP", + "offset": 32 + }, + "use-content-height": true + } + }, + { + "type": "ColumnLayout", + "id": "moduleSelectLayout", + "columns": 2, + "column-widths": [0.7, 0.3], + "horizontalSpacing": 16, + "contents": [ + { + "type": "ScrollableArea", + "content": { + "type": "UIList", + "id": "modulesList", + "family": "menuButtons" + } + }, + { + "type": "RelativeLayout", + "id": "moduleActionButtons", + "contents": [ + { + "type": "UIButton", + "id": "activateButton", + "text": "Activate Module", + "layoutInfo": { + "position-bottom": { + "target": "MIDDLE", + "offset": 5 + }, + "use-content-height": true + } + }, + { + "type": "UIButton", + "id": "deactivateButton", + "text": "Deactivate Module", + "layoutInfo": { + "position-top": { + "target": "MIDDLE", + "offset": 5 + }, + "use-content-height": true + } + } + ] + } + ], + "layoutInfo": { + "position-horizontal-center": {}, + "position-bottom": { + "widget": "confirmButton", + "target": "TOP", + "offset": 16 + }, + "position-top": { + "widget": "headerText", + "target": "BOTTOM", + "offset": 16 + }, + "position-left": { + "offset": 16 + }, + "position-right": { + "offset": 16 + } + } + }, + { + "type": "UIButton", + "id": "confirmButton", + "text": "Confirm", + "layoutInfo": { + "position-bottom": { + "offset": 32 + }, + "position-left": { + "offset": 32 + }, + "position-right": { + "offset": 32 + }, + "use-content-height": true + } + } + ] + } +} \ No newline at end of file diff --git a/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/newShipScreen.ui b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/newShipScreen.ui index 36e8d2454..eed5dd8d8 100644 --- a/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/newShipScreen.ui +++ b/engine/src/main/resources/org/destinationsol/assets/ui/mainMenu/newShipScreen.ui @@ -74,6 +74,18 @@ "use-content-height": true, "use-content-width": true } + }, + { + "type": "UIButton", + "id": "modulesButton", + "family": "modulesButton", + "text": "Modules", + "layoutInfo": { + "position-right": {}, + "position-bottom": {}, + "width": 100, + "height": 50 + } } ] } From 462ff0c6b084ce6e1d36250f946eeeb6f382dc80 Mon Sep 17 00:00:00 2001 From: BenjaminAmos <24301287+BenjaminAmos@users.noreply.github.com> Date: Fri, 10 Jan 2025 20:19:08 +0000 Subject: [PATCH 19/24] feat!(factions): factions system re-work (#703) * feat!(factions): factions system re-work Factions are now defined independently and can hold relations with each other. The player has their own faction which holds separate relationships with each faction. Factions holding a poor reputation will be hostile. The original Faction enum has been removed and FactionInfo's functionality has been moved into FactionManager, with data now held in a new Faction class. This is a foundation for future work and does not expose any new gameplay. --- .../org/destinationsol/FactionDisplay.java | 7 +- .../SolGameServiceRegistry.java | 2 + .../org/destinationsol/assets/json/Json.java | 2 +- .../java/org/destinationsol/game/Faction.java | 29 --- .../org/destinationsol/game/FactionInfo.java | 104 ---------- .../destinationsol/game/FactionManager.java | 122 +++++++++++- .../org/destinationsol/game/GalaxyFiller.java | 17 +- .../java/org/destinationsol/game/Hero.java | 5 + .../org/destinationsol/game/MapDrawer.java | 1 + .../destinationsol/game/PlayerCreator.java | 10 +- .../java/org/destinationsol/game/SolGame.java | 2 - .../game/chunk/ChunkFiller.java | 3 +- .../game/faction/DefaultReputationEvent.java | 54 ++++++ .../destinationsol/game/faction/Faction.java | 179 ++++++++++++++++++ .../game/faction/FactionConfig.java | 46 +++++ .../game/faction/FactionsConfigs.java | 70 +++++++ .../game/faction/ReputationEvent.java | 34 ++++ .../org/destinationsol/game/gun/GunMount.java | 2 +- .../org/destinationsol/game/gun/SolGun.java | 2 +- .../destinationsol/game/input/AiPilot.java | 14 +- .../org/destinationsol/game/input/Pilot.java | 4 +- .../game/input/UiControlledPilot.java | 14 +- .../destinationsol/game/maze/MazeBuilder.java | 3 +- .../game/planet/PlanetObjectsBuilder.java | 12 +- .../game/projectile/Projectile.java | 5 +- .../game/screens/BorderDrawer.java | 2 +- .../game/screens/BuyItemsScreen.java | 4 +- .../org/destinationsol/game/ship/Door.java | 2 +- .../destinationsol/game/ship/ForceBeacon.java | 2 +- .../destinationsol/game/ship/ShipBuilder.java | 17 +- .../org/destinationsol/game/ship/SolShip.java | 24 +-- .../destinationsol/game/ship/Teleport.java | 2 +- .../destinationsol/game/ship/hulls/Hull.java | 2 +- .../steps/DestroySpawnedShipsStep.java | 3 +- .../mercenary/MercenaryUtils.java | 3 +- .../assets/configs/factions.json | 5 + .../destinationsol/assets/factions/ehar.json | 7 + .../destinationsol/assets/factions/laani.json | 7 + .../assets/factions/player.json | 7 + .../assets/schemas/schemaFaction.json | 38 ++++ .../assets/schemas/schemaFactions.json | 40 +--- modules/core/assets/configs/factions.json | 77 +------- .../core/assets/configs/systemsConfig.json | 2 +- modules/core/assets/factions/desert.json | 14 ++ modules/core/assets/factions/imperial.json | 14 ++ modules/core/assets/factions/miner.json | 12 ++ modules/core/assets/factions/pirate.json | 14 ++ modules/core/assets/factions/techie.json | 11 ++ modules/core/assets/factions/trader.json | 10 + .../miner.json => minerGun/minerGun.json} | 0 .../miner.png => minerGun/minerGun.png} | Bin .../minerGunIcon.png} | Bin 52 files changed, 715 insertions(+), 347 deletions(-) delete mode 100644 engine/src/main/java/org/destinationsol/game/Faction.java delete mode 100644 engine/src/main/java/org/destinationsol/game/FactionInfo.java create mode 100644 engine/src/main/java/org/destinationsol/game/faction/DefaultReputationEvent.java create mode 100644 engine/src/main/java/org/destinationsol/game/faction/Faction.java create mode 100644 engine/src/main/java/org/destinationsol/game/faction/FactionConfig.java create mode 100644 engine/src/main/java/org/destinationsol/game/faction/FactionsConfigs.java create mode 100644 engine/src/main/java/org/destinationsol/game/faction/ReputationEvent.java create mode 100644 engine/src/main/resources/org/destinationsol/assets/configs/factions.json create mode 100644 engine/src/main/resources/org/destinationsol/assets/factions/ehar.json create mode 100644 engine/src/main/resources/org/destinationsol/assets/factions/laani.json create mode 100644 engine/src/main/resources/org/destinationsol/assets/factions/player.json create mode 100644 engine/src/main/resources/org/destinationsol/assets/schemas/schemaFaction.json create mode 100644 modules/core/assets/factions/desert.json create mode 100644 modules/core/assets/factions/imperial.json create mode 100644 modules/core/assets/factions/miner.json create mode 100644 modules/core/assets/factions/pirate.json create mode 100644 modules/core/assets/factions/techie.json create mode 100644 modules/core/assets/factions/trader.json rename modules/core/assets/items/guns/{miner/miner.json => minerGun/minerGun.json} (100%) rename modules/core/assets/items/guns/{miner/miner.png => minerGun/minerGun.png} (100%) rename modules/core/assets/items/guns/{miner/minerIcon.png => minerGun/minerGunIcon.png} (100%) diff --git a/engine/src/main/java/org/destinationsol/FactionDisplay.java b/engine/src/main/java/org/destinationsol/FactionDisplay.java index db448e813..a187d722a 100644 --- a/engine/src/main/java/org/destinationsol/FactionDisplay.java +++ b/engine/src/main/java/org/destinationsol/FactionDisplay.java @@ -17,9 +17,7 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; -import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.Vector2; -import org.destinationsol.game.FactionInfo; import org.destinationsol.game.ObjectManager; import org.destinationsol.game.SolCam; import org.destinationsol.game.SolGame; @@ -27,6 +25,7 @@ import org.destinationsol.game.ship.SolShip; import org.destinationsol.ui.SolInputManager; import org.destinationsol.ui.UiDrawer; +import org.terasology.nui.backends.libgdx.GdxColorUtil; /** * Acquires faction information fromm all the ships and draws it above them. @@ -49,8 +48,8 @@ public void drawFactionNames(SolGame game, UiDrawer uiDrawer, SolInputManager in if (obj instanceof SolShip) { SolShip ship = (SolShip) obj; Vector2 drawPosition = camera.worldToScreen(ship); - uiDrawer.drawString(ship.getFactionName(), drawPosition.x * SolApplication.displayDimensions.getRatio(), - drawPosition.y - .1f, 1, false, Color.valueOf(FactionInfo.getFactionColors().get(ship.getFactionID()).toString())); + uiDrawer.drawString(ship.getFaction().getName(), drawPosition.x * SolApplication.displayDimensions.getRatio(), + drawPosition.y - .1f, 1, false, GdxColorUtil.terasologyToGDXColor(ship.getFaction().getColour())); } } } diff --git a/engine/src/main/java/org/destinationsol/SolGameServiceRegistry.java b/engine/src/main/java/org/destinationsol/SolGameServiceRegistry.java index 0e6485e74..97c0cdb8f 100644 --- a/engine/src/main/java/org/destinationsol/SolGameServiceRegistry.java +++ b/engine/src/main/java/org/destinationsol/SolGameServiceRegistry.java @@ -37,6 +37,7 @@ import org.destinationsol.game.chunk.ChunkManager; import org.destinationsol.game.drawables.DrawableDebugger; import org.destinationsol.game.drawables.DrawableManager; +import org.destinationsol.game.faction.FactionsConfigs; import org.destinationsol.game.farBg.FarBackgroundManagerOld; import org.destinationsol.game.item.ItemManager; import org.destinationsol.game.item.LootBuilder; @@ -69,6 +70,7 @@ public SolGameServiceRegistry(boolean isTutorial) { this.with(ShipBuilder.class).lifetime(Lifetime.Singleton); this.with(GridDrawer.class).lifetime(Lifetime.Singleton); this.with(FarBackgroundManagerOld.class).lifetime(Lifetime.Singleton); + this.with(FactionsConfigs.class).lifetime(Lifetime.Singleton); this.with(FactionManager.class).lifetime(Lifetime.Singleton); this.with(MapDrawer.class).lifetime(Lifetime.Singleton); this.with(RubbleBuilder.class).lifetime(Lifetime.Singleton); diff --git a/engine/src/main/java/org/destinationsol/assets/json/Json.java b/engine/src/main/java/org/destinationsol/assets/json/Json.java index 9a85b5714..c1d670efb 100644 --- a/engine/src/main/java/org/destinationsol/assets/json/Json.java +++ b/engine/src/main/java/org/destinationsol/assets/json/Json.java @@ -21,7 +21,7 @@ import org.terasology.gestalt.assets.ResourceUrn; import org.terasology.gestalt.assets.module.annotations.RegisterAssetType; -@RegisterAssetType(folderName = {"collisionMeshes", "ships", "items", "configs", "grounds", "mazes", "asteroids", "schemas"}, factoryClass = JsonFactory.class) +@RegisterAssetType(folderName = {"collisionMeshes", "ships", "factions", "items", "configs", "grounds", "mazes", "asteroids", "schemas"}, factoryClass = JsonFactory.class) public class Json extends Asset { private JsonData jsonData; diff --git a/engine/src/main/java/org/destinationsol/game/Faction.java b/engine/src/main/java/org/destinationsol/game/Faction.java deleted file mode 100644 index b09af6202..000000000 --- a/engine/src/main/java/org/destinationsol/game/Faction.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.destinationsol.game; - -public enum Faction { - LAANI("laani"), EHAR("ehar"); - private final String myName; - - Faction(String name) { - myName = name; - } - - public String getName() { - return myName; - } -} diff --git a/engine/src/main/java/org/destinationsol/game/FactionInfo.java b/engine/src/main/java/org/destinationsol/game/FactionInfo.java deleted file mode 100644 index c1c317aab..000000000 --- a/engine/src/main/java/org/destinationsol/game/FactionInfo.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2018 MovingBlocks - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.destinationsol.game; - -import org.destinationsol.assets.Assets; -import org.destinationsol.assets.json.Json; -import org.destinationsol.assets.json.Validator; -import org.destinationsol.game.ship.SolShip; -import org.json.JSONArray; -import org.terasology.gestalt.assets.ResourceUrn; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; - -/** - * Loads ands stores faction data - */ -public class FactionInfo { - private static ArrayList factionName = new ArrayList(); - private static ArrayList factionColor = new ArrayList(); - private static ArrayList factionDisposition = new ArrayList(); - - public static void init() { - createFactionList(); - } - - private static void createFactionList() { - for (String modulePath : getModuleSet()) { - Json factionJson = Assets.getJson(modulePath); - Validator.getValidatedJSON(modulePath, "engine:schemaFactions"); - JSONArray factionJsonArray = factionJson.getJsonValue().getJSONArray("factions"); - for (int n = 0; n < factionJsonArray.length(); n++) { - factionName.add(factionJsonArray.getJSONObject(n).getString("name").replace("\"", "")); - factionColor.add(factionJsonArray.getJSONObject(n).getString("color").replace("\"", "")); - factionDisposition.add(factionJsonArray.getJSONObject(n).getInt("disposition")); - } - } - } - - private static Set getModuleSet() { - Set moduleSet = new HashSet(); - Set moduleUrn = Assets.getAssetHelper().listAssets(Json.class, "factions"); - for (ResourceUrn module : moduleUrn) { - moduleSet.add(module.toString()); - } - return moduleSet; - } - - public static void clearValues() { - factionName.clear(); - factionColor.clear(); - factionDisposition.clear(); - } - - public static ArrayList getFactionNames() { - return factionName; - } - - public static ArrayList getFactionColors() { - return factionColor; - } - - public static int getFactionID(SolShip ship) { - String shipName = ship.getHull().getHullConfig().getInternalName(); - for (String modulePath : getModuleSet()) { - Json factionJson = Assets.getJson(modulePath); - Validator.getValidatedJSON(modulePath, "engine:schemaFactions"); - JSONArray factionJsonArray = factionJson.getJsonValue().getJSONArray("factions"); - shipName = shipName.replaceAll(".*:", ""); - for (int n = 0; n < factionJsonArray.length(); n++) { - for (int z = 0; z < factionJsonArray.getJSONObject(n).getJSONArray("ships").length(); z++) { - if (shipName.equals(factionJsonArray.getJSONObject(n).getJSONArray("ships").get(z))) { - return n; - } - } - } - } - return 0; - } - - public static ArrayList getDisposition() { - return factionDisposition; - } - - public static void setDisposition(int n, int num) { - if (factionDisposition.get(n) <= 100) { - factionDisposition.set(n, factionDisposition.get(n) + num); - } - } -} diff --git a/engine/src/main/java/org/destinationsol/game/FactionManager.java b/engine/src/main/java/org/destinationsol/game/FactionManager.java index 886a04f99..45ccc0cce 100644 --- a/engine/src/main/java/org/destinationsol/game/FactionManager.java +++ b/engine/src/main/java/org/destinationsol/game/FactionManager.java @@ -18,24 +18,105 @@ import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.physics.box2d.Fixture; import com.badlogic.gdx.physics.box2d.RayCastCallback; +import org.destinationsol.game.faction.Faction; +import org.destinationsol.game.faction.FactionsConfigs; +import org.destinationsol.game.faction.ReputationEvent; import org.destinationsol.game.input.Pilot; import org.destinationsol.game.projectile.Projectile; import org.destinationsol.game.ship.SolShip; +import org.destinationsol.game.ship.hulls.HullConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.terasology.gestalt.assets.ResourceUrn; import javax.inject.Inject; +import java.util.ArrayList; import java.util.List; +/** + * The faction manager is responsible for managing all factions in the game. + */ public class FactionManager { - + private static final Logger logger = LoggerFactory.getLogger(FactionManager.class); + private static final ResourceUrn PLAYER_FACTION_URN = new ResourceUrn("engine:player"); + private static final ResourceUrn GENERIC_ALLY_FACTION_URN = new ResourceUrn("engine:laani"); + private static final ResourceUrn GENERIC_ENEMY_FACTION_URN = new ResourceUrn("engine:ehar"); private final MyRayBack myRayBack; + private final List factions; + private Faction playerFaction; + private Faction genericAllyFaction; + private Faction genericEnemyFaction; @Inject - public FactionManager() { + public FactionManager(FactionsConfigs factionsConfigs) { myRayBack = new MyRayBack(); + factions = new ArrayList<>(factionsConfigs.factionConfigs.values()); + for (Faction faction : factions) { + if (faction.getId().equals(PLAYER_FACTION_URN)) { + playerFaction = faction; + } else if (faction.getId().equals(GENERIC_ALLY_FACTION_URN)) { + genericAllyFaction = faction; + } else if (faction.getId().equals(GENERIC_ENEMY_FACTION_URN)) { + genericEnemyFaction = faction; + } + } + } + + /** + * Reports an event that may influence relations between two factions. + * @param instigator the instigating faction that triggered the event. + * @param target the faction targeted by the event. + * @param event the event that occurred. + * @param the type of event. + */ + public & ReputationEvent> void reportEvent(Faction instigator, Faction target, T event) { + // TODO: Add support for custom event handlers. + // Some examples: + // - A pacifist faction is offended by any attacks made by a faction, regardless of the target. + // - A merchant faction may randomly give a free bonus when buying items. + // - A protective faction may dispatch a fleet to intercept the attacker if one of their ships is attacked. + Integer targetReputationImpact = target.getReputationImpact(event); + if (targetReputationImpact != null) { + target.setRelation(instigator, target.getRelation(instigator) + targetReputationImpact); + } else { + target.setRelation(instigator, target.getRelation(instigator) + event.getDefaultReputationImpact()); + } } /** - * Finds the nearest Enemy @{link SolShip} for the given ship + * Returns all known factions. + * @return all known factions. + */ + public Iterable getFactions() { + return factions; + } + + /** + * Returns the player's personal faction. + * @return the player's personal faction. + */ + public Faction getPlayerFaction() { + return playerFaction; + } + + /** + * Returns the built-in generic ally faction, which is friendly with everyone. + * @return the generic ally faction. + */ + public Faction getGenericAllyFaction() { + return genericAllyFaction; + } + + /** + * Returns the built-in generic enemy faction, which is hostile to everyone (except themselves). + * @return the generic enemy faction. + */ + public Faction getGenericEnemyFaction() { + return genericEnemyFaction; + } + + /** + * Finds the nearest Enemy {@link SolShip} for the given ship * * @param game the game object * @param ship the ship to find enemies for @@ -48,8 +129,8 @@ public SolShip getNearestEnemy(SolGame game, SolShip ship) { return null; } detectionDist += ship.getHull().config.getApproxRadius(); - Faction f = pilot.getFaction(); - return getNearestEnemy(game, detectionDist, f, ship.getPosition()); + Faction faction = pilot.getFaction(); + return getNearestEnemy(game, detectionDist, faction, ship.getPosition()); } /** @@ -64,7 +145,7 @@ public SolShip getNearestEnemy(SolGame game, Projectile projectile) { } /** - * Finds the nearest Enemy @{link SolShip} + * Finds the nearest Enemy {@link SolShip} * * @param game the game object * @param detectionDist the maximum distance allowed for detection @@ -94,6 +175,21 @@ public SolShip getNearestEnemy(SolGame game, float detectionDist, Faction factio return nearestEnemyShip; } + /** + * Returns a faction capable of constructing the given hull. + * @param hull the hull to be constructed. + * @return a faction capable of constructing the given hull, if found, otherwise null. + */ + public Faction getBuilderForHull(HullConfig hull) { + for (Faction faction : factions) { + if (faction.getShipDesigns().contains(new ResourceUrn(hull.getInternalName()))) { + return faction; + } + } + logger.error("Failed to find faction that produces hull: {}", hull.getInternalName()); + return null; + } + private boolean hasObstacles(SolGame game, SolShip shipFrom, SolShip shipTo) { myRayBack.shipFrom = shipFrom; myRayBack.shipTo = shipTo; @@ -102,14 +198,26 @@ private boolean hasObstacles(SolGame game, SolShip shipFrom, SolShip shipTo) { return myRayBack.hasObstacle; } + /** + * Specifies whether two ships are enemies to each other. + * @param s1 the first ship. + * @param s2 the second ship. + * @return true, if s1 and s1 are enemies, otherwise false. + */ public boolean areEnemies(SolShip s1, SolShip s2) { Faction f1 = s1.getPilot().getFaction(); Faction f2 = s2.getPilot().getFaction(); return areEnemies(f1, f2); } + /** + * Specifies whether two factions are enemies of each other. + * @param f1 the first faction. + * @param f2 the second faction. + * @return true, if f1 and f2 are enemies, otherwise false. + */ public boolean areEnemies(Faction f1, Faction f2) { - return f1 != null && f2 != null && f1 != f2; + return f1 != null && f2 != null && f1.getRelation(f2) < 0; } private static class MyRayBack implements RayCastCallback { diff --git a/engine/src/main/java/org/destinationsol/game/GalaxyFiller.java b/engine/src/main/java/org/destinationsol/game/GalaxyFiller.java index f57fb8df5..b78984f44 100644 --- a/engine/src/main/java/org/destinationsol/game/GalaxyFiller.java +++ b/engine/src/main/java/org/destinationsol/game/GalaxyFiller.java @@ -22,6 +22,7 @@ import org.destinationsol.common.SolMath; import org.destinationsol.common.SolRandom; import org.destinationsol.files.HullConfigManager; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.input.AiPilot; import org.destinationsol.game.input.ExplorerDestProvider; import org.destinationsol.game.input.Guardian; @@ -85,6 +86,7 @@ private Vector2 getPosForStation(SolarSystem sys, boolean mainStation, ConsumedA private FarShip build(SolGame game, ShipConfig config, Faction faction, boolean mainStation, SolarSystem system, ConsumedAngles angles) { HullConfig hullConf = config.hull; + boolean isPlayerAlly = game.getFactionMan().getPlayerFaction().getRelation(faction) >= 0; MoveDestProvider destProvider; Vector2 position; @@ -99,7 +101,7 @@ private FarShip build(SolGame game, ShipConfig config, Faction faction, boolean boolean isBig = hullConf.getType() == HullConfig.Type.BIG; destProvider = new ExplorerDestProvider(position, !isBig, hullConf, system); if (isBig) { - if (faction == Faction.LAANI) { + if (isPlayerAlly) { tradeConfig = system.getConfig().tradeConfig; } } else { @@ -109,7 +111,7 @@ private FarShip build(SolGame game, ShipConfig config, Faction faction, boolean Pilot pilot = new AiPilot(destProvider, true, faction, true, "something", detectionDist); float angle = mainStation ? 0 : SolRandom.seededRandomFloat(180); boolean hasRepairer; - hasRepairer = faction == Faction.LAANI; + hasRepairer = isPlayerAlly; int money = config.money; FarShip ship = game.getShipBuilder().buildNewFar(game, position, null, angle, 0, pilot, config.items, hullConf, null, hasRepairer, money, tradeConfig, true); game.getObjectManager().addFarObjNow(ship); @@ -148,7 +150,8 @@ public void fill(SolGame game, HullConfigManager hullConfigManager, ItemManager ShipConfig mainStationCfg = ShipConfig.load(hullConfigManager, rootNode, itemManager); ConsumedAngles angles = new ConsumedAngles(); - FarShip mainStation = build(game, mainStationCfg, Faction.LAANI, true, systems.get(0), angles); + // TODO: Select an appropriate enemy faction based on the player faction. + FarShip mainStation = build(game, mainStationCfg, game.getFactionMan().getBuilderForHull(mainStationCfg.hull), true, systems.get(0), angles); mainStationPos.set(mainStation.getPosition()); mainStationHc = mainStation.getHullConfig(); @@ -158,14 +161,16 @@ public void fill(SolGame game, HullConfigManager hullConfigManager, ItemManager for (ShipConfig shipConfig : solarSystemConfig.constAllies) { int count = (int) (shipConfig.density); for (int i = 0; i < count; i++) { - build(game, shipConfig, Faction.LAANI, false, system, angles); + // TODO: Select an appropriate ally faction based on the player faction. + build(game, shipConfig, game.getFactionMan().getBuilderForHull(shipConfig.hull), false, system, angles); } } for (ShipConfig shipConfig : solarSystemConfig.constEnemies) { int count = (int) (shipConfig.density); for (int i = 0; i < count; i++) { - build(game, shipConfig, Faction.EHAR, false, system, angles); + // TODO: Select an appropriate enemy faction based on the player faction. + build(game, shipConfig, game.getFactionMan().getBuilderForHull(mainStationCfg.hull), false, system, angles); } } @@ -227,7 +232,7 @@ private void link(SolGame game, Planet firstPlanet, Planet secondPlanet) { private void createGuard(SolGame game, FarShip target, ShipConfig guardConfig, Faction faction, float guardRelAngle) { Guardian dp = new Guardian(game, guardConfig.hull, target.getPilot(), target.getPosition(), target.getHullConfig(), guardRelAngle); Pilot pilot = new AiPilot(dp, true, faction, false, null, Const.AI_DET_DIST); - boolean hasRepairer = faction == Faction.LAANI; + boolean hasRepairer = game.getFactionMan().getPlayerFaction().getRelation(faction) >= 0; int money = guardConfig.money; FarShip enemy = game.getShipBuilder().buildNewFar(game, dp.getDestination(), null, guardRelAngle, 0, pilot, guardConfig.items, guardConfig.hull, null, hasRepairer, money, null, true); diff --git a/engine/src/main/java/org/destinationsol/game/Hero.java b/engine/src/main/java/org/destinationsol/game/Hero.java index ffe652575..cc5444eab 100644 --- a/engine/src/main/java/org/destinationsol/game/Hero.java +++ b/engine/src/main/java/org/destinationsol/game/Hero.java @@ -19,6 +19,7 @@ import org.destinationsol.GameOptions; import org.destinationsol.assets.music.OggMusicManager; import org.destinationsol.common.SolException; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.input.Pilot; import org.destinationsol.game.item.Armor; import org.destinationsol.game.item.ItemContainer; @@ -103,6 +104,10 @@ public SolShip getShipUnchecked() { return shipHero; } + public Faction getFaction() { + return getPilot().getFaction(); + } + public StarPort.Transcendent getTranscendentHero() { if (!isTranscendent) { throw new SolException("Something is trying to get a Transcendent hero while the hero is in SolShip state."); diff --git a/engine/src/main/java/org/destinationsol/game/MapDrawer.java b/engine/src/main/java/org/destinationsol/game/MapDrawer.java index 4292de859..d1c5b95b6 100644 --- a/engine/src/main/java/org/destinationsol/game/MapDrawer.java +++ b/engine/src/main/java/org/destinationsol/game/MapDrawer.java @@ -28,6 +28,7 @@ import org.destinationsol.common.SolColor; import org.destinationsol.common.SolMath; import org.destinationsol.game.context.Context; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.maze.Maze; import org.destinationsol.game.maze.MazeBuilder; import org.destinationsol.game.planet.FarTileObject; diff --git a/engine/src/main/java/org/destinationsol/game/PlayerCreator.java b/engine/src/main/java/org/destinationsol/game/PlayerCreator.java index 6be256014..c5d344cb8 100644 --- a/engine/src/main/java/org/destinationsol/game/PlayerCreator.java +++ b/engine/src/main/java/org/destinationsol/game/PlayerCreator.java @@ -18,6 +18,7 @@ import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.Vector2; import org.destinationsol.Const; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.input.AiPilot; import org.destinationsol.game.input.BeaconDestProvider; import org.destinationsol.game.input.Pilot; @@ -51,7 +52,8 @@ Hero createPlayer(ShipConfig shipConfig, boolean shouldSpawnOnGalaxySpawnPositio } private Hero configureAndCreateHero(ShipConfig shipConfig, RespawnState respawnState, SolGame game, boolean isMouseControl, boolean isNewShip, Vector2 position) { - Pilot pilot = createPilot(game, isMouseControl); + Faction faction = game.getFactionMan().getPlayerFaction(); + Pilot pilot = createPilot(game, faction, isMouseControl); float money = grantPlayerMoney(shipConfig, respawnState, game); HullConfig hull = findHullConfig(shipConfig, respawnState); String items = findItems(shipConfig, respawnState); @@ -167,11 +169,11 @@ private float grantPlayerMoney(ShipConfig shipConfig, RespawnState respawnState, return shipConfig.getMoney(); } - private Pilot createPilot(SolGame game, boolean isMouseControl) { + private Pilot createPilot(SolGame game, Faction faction, boolean isMouseControl) { if (isMouseControl) { - return new AiPilot(new BeaconDestProvider(), true, Faction.LAANI, false, "you", Const.AI_DET_DIST); + return new AiPilot(new BeaconDestProvider(), true, faction, false, "you", Const.AI_DET_DIST); } else { - return new UiControlledPilot(game.getScreens().getOldMainGameScreen().getShipControl()); + return new UiControlledPilot(faction, game.getScreens().getOldMainGameScreen().getShipControl()); } } diff --git a/engine/src/main/java/org/destinationsol/game/SolGame.java b/engine/src/main/java/org/destinationsol/game/SolGame.java index 9cf9518f6..f6fb6c94c 100644 --- a/engine/src/main/java/org/destinationsol/game/SolGame.java +++ b/engine/src/main/java/org/destinationsol/game/SolGame.java @@ -168,7 +168,6 @@ public MainGameScreen getMainGameScreen() { @Inject public SolGame(SolApplication solApplication, PlanetConfigManager planetConfigManager, MazeConfigManager mazeConfigManager, BeltConfigManager beltConfigManager) { - FactionInfo.init(); this.solApplication = solApplication; boolean isMobile = solApplication.isMobile(); @@ -344,7 +343,6 @@ public void onGameEnd(Context context) { // TODO: Remove this when context is reset after each game context.get(EntitySystemManager.class).getEntityManager().allEntities().forEach(EntityRef::delete); - FactionInfo.clearValues(); try { objectManager.close(); } catch (Exception e) { diff --git a/engine/src/main/java/org/destinationsol/game/chunk/ChunkFiller.java b/engine/src/main/java/org/destinationsol/game/chunk/ChunkFiller.java index 7a79e569c..e7a56b8f6 100644 --- a/engine/src/main/java/org/destinationsol/game/chunk/ChunkFiller.java +++ b/engine/src/main/java/org/destinationsol/game/chunk/ChunkFiller.java @@ -24,7 +24,6 @@ import org.destinationsol.common.SolMath; import org.destinationsol.common.SolRandom; import org.destinationsol.game.DebugOptions; -import org.destinationsol.game.Faction; import org.destinationsol.game.RemoveController; import org.destinationsol.game.ShipConfig; import org.destinationsol.game.SolGame; @@ -197,7 +196,7 @@ private FarShip buildSpaceEnemy(SolGame game, Vector2 position, RemoveController SolMath.fromAl(velocity, SolRandom.randomFloat(180), SolRandom.randomFloat(0, ENEMY_MAX_SPD)); float rotationSpeed = SolRandom.randomFloat(ENEMY_MAX_ROT_SPD); MoveDestProvider dp = new StillGuard(position, game, enemyConf); - Pilot provider = new AiPilot(dp, false, Faction.EHAR, true, null, Const.AI_DET_DIST); + Pilot provider = new AiPilot(dp, false, game.getFactionMan().getBuilderForHull(enemyConf.hull), true, null, Const.AI_DET_DIST); HullConfig config = enemyConf.hull; int money = enemyConf.money; float angle = SolRandom.randomFloat(180); diff --git a/engine/src/main/java/org/destinationsol/game/faction/DefaultReputationEvent.java b/engine/src/main/java/org/destinationsol/game/faction/DefaultReputationEvent.java new file mode 100644 index 000000000..6cdade7e3 --- /dev/null +++ b/engine/src/main/java/org/destinationsol/game/faction/DefaultReputationEvent.java @@ -0,0 +1,54 @@ +/* + * Copyright 2025 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.destinationsol.game.faction; + +/** + * Defines events impacting reputation that are likely to be used by the base game. + */ +public enum DefaultReputationEvent implements ReputationEvent { + /** + * A ship (or projectile fired by a ship) has caused damage to another. + */ + DAMAGED_SHIP(-1), + /** + * A ship (or projectile fired by a ship) has destroyed another. + */ + DESTROYED_SHIP(-20), + /** + * A ship has bought an item from a station. + * (Note: this only applies to the player for now.) + */ + BOUGHT_ITEM(1); + + /** + * The default impact on reputation this event will have in absence of a faction-specific value. + */ + private final int defaultReputationImpact; + + DefaultReputationEvent(int defaultReputationImpact) { + this.defaultReputationImpact = defaultReputationImpact; + } + + /** + * Returns the default impact on reputation this event will have in absence of a faction-specific value. + * @return the default impact on reputation this event will have in absence of a faction-specific value. + */ + @Override + public int getDefaultReputationImpact() { + return defaultReputationImpact; + } +} diff --git a/engine/src/main/java/org/destinationsol/game/faction/Faction.java b/engine/src/main/java/org/destinationsol/game/faction/Faction.java new file mode 100644 index 000000000..b321be654 --- /dev/null +++ b/engine/src/main/java/org/destinationsol/game/faction/Faction.java @@ -0,0 +1,179 @@ +/* + * Copyright 2025 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.destinationsol.game.faction; + +import org.joml.Math; +import org.terasology.gestalt.assets.ResourceUrn; +import org.terasology.nui.Color; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A faction is an abstraction used to establish common diplomatic relations between aligned entities. + * Factions hold an overall disposition towards other factions, which determines their approach towards entities + * belonging to those factions. Factions holding a negative disposition towards others will be openly hostile. + */ +public class Faction { + /** + * The minimum possible reputation a faction can have with another. + */ + public static final int MIN_REPUTATION = -100; + /** + * The maximum possible reputation a faction can have with another. + */ + public static final int MAX_REPUTATION = 100; + /** + * The identifier used to uniquely identify this faction (e.g. "my-faction") + */ + private final ResourceUrn id; + /** + * The name of this faction. + */ + private final String name; + /** + * The faction's description. + */ + private final String description; + /** + * The faction's primary colour. + */ + private final Color colour; + /** + * Ship designs that can be produced by this faction. + */ + private final List shipDesigns; + /** + * The default standing that this faction has towards unknown factions. + */ + private final int defaultDisposition; + /** + * The relations held between this faction and other factions. + */ + private final Map relations; + /** + * The impact that certain events will have on relations with another faction if they instigate a given event. + * (For example, hitting the ship with a projectile loses reputation, having a negative impact.) + * @see DefaultReputationEvent + */ + private final Map reputationImpacts; + + /** + * Instantiates a new faction instance. + * @param id the faction's id (this should be the urn corresponding to the faction's JSON definition file) + * @param name the name of the faction + * @param description a description for the faction + * @param colour the faction's primary colour + * @param defaultDisposition the faction's default disposition towards unknown factions + * @param shipDesigns ship designs that can be built by this faction + * @param reputationImpacts the impact certain events should have on relationships between this faction and others. + */ + public Faction(ResourceUrn id, String name, String description, Color colour, int defaultDisposition, + List shipDesigns, Map reputationImpacts) { + this.id = id; + this.name = name; + this.description = description; + this.colour = colour; + this.defaultDisposition = Math.clamp(MIN_REPUTATION, MAX_REPUTATION, defaultDisposition); + this.shipDesigns = shipDesigns; + this.relations = new HashMap<>(); + this.reputationImpacts = reputationImpacts; + } + + /** + * Returns the faction's id. + * @return the faction's id. + */ + public ResourceUrn getId() { + return id; + } + + /** + * Returns the faction's name. + * @return the faction's name. + */ + public String getName() { + return name; + } + + /** + * Returns the faction's description. + * @return the faction's description. + */ + public String getDescription() { + return description; + } + + /** + * Returns the faction's primary colour. + * @return the faction's primary colour. + */ + public Color getColour() { + return colour; + } + + /** + * Returns a list of ship designs that can be manufactured by the faction. + * @return a list of ship designs that this faction can make. + */ + public List getShipDesigns() { + return shipDesigns; + } + + /** + * Gets the impact of an event on this faction's relationships with others. + * @param event the event to query. + * @return the change in reputation, if known, otherwise null. + * @param the type of event. + */ + public & ReputationEvent> Integer getReputationImpact(T event) { + return reputationImpacts.get(event.toString()); + } + + /** + * Specifies whether a faction has formal relations with another (meaning they have an explicit reputation built-up). + * @param faction the faction to check. + * @return true, if the faction is known to this faction, otherwise false. + */ + public boolean isAwareOf(Faction faction) { + return relations.containsKey(faction); + } + + /** + * Returns the reputation held by another faction with this faction. + * @param faction the faction to check. + * @return the reputation value held with this faction. + */ + public int getRelation(Faction faction) { + if (faction == this) { + return MAX_REPUTATION; + } + return relations.getOrDefault(faction, defaultDisposition); + } + + /** + * Sets the reputation held by this faction for another. + * @param faction the faction to assign reputation with. + * @param disposition the overall disposition of this faction towards the other. + */ + public void setRelation(Faction faction, int disposition) { + if (faction != this) { + relations.put(faction, Math.clamp(MIN_REPUTATION, MAX_REPUTATION, disposition)); + } + } +} diff --git a/engine/src/main/java/org/destinationsol/game/faction/FactionConfig.java b/engine/src/main/java/org/destinationsol/game/faction/FactionConfig.java new file mode 100644 index 000000000..9b2c48b75 --- /dev/null +++ b/engine/src/main/java/org/destinationsol/game/faction/FactionConfig.java @@ -0,0 +1,46 @@ +/* + * Copyright 2025 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.destinationsol.game.faction; + +import com.badlogic.gdx.graphics.Color; +import org.json.JSONArray; +import org.json.JSONObject; +import org.terasology.gestalt.assets.ResourceUrn; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class FactionConfig { + private FactionConfig() { + } + + public static Faction load(ResourceUrn id, JSONObject jsonObject) { + Color gdxColour = Color.valueOf(jsonObject.getString("colour")); + List shipDesigns = new ArrayList<>(); + JSONArray shipDesignsArray = jsonObject.getJSONArray("shipDesigns"); + for (int designNo = 0; designNo < shipDesignsArray.length(); designNo++) { + shipDesigns.add(new ResourceUrn(shipDesignsArray.getString(designNo))); + } + Map reputationImpacts = new HashMap<>(); + return new Faction(id, jsonObject.getString("name"), + jsonObject.getString("description"), + new org.terasology.nui.Color(gdxColour.r, gdxColour.g, gdxColour.b, gdxColour.a), + jsonObject.optInt("defaultDisposition", 0), shipDesigns, reputationImpacts); + } +} diff --git a/engine/src/main/java/org/destinationsol/game/faction/FactionsConfigs.java b/engine/src/main/java/org/destinationsol/game/faction/FactionsConfigs.java new file mode 100644 index 000000000..019fbc7b1 --- /dev/null +++ b/engine/src/main/java/org/destinationsol/game/faction/FactionsConfigs.java @@ -0,0 +1,70 @@ +/* + * Copyright 2025 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.destinationsol.game.faction; + +import org.destinationsol.assets.AssetHelper; +import org.destinationsol.assets.json.Json; +import org.destinationsol.assets.json.Validator; +import org.json.JSONObject; +import org.terasology.gestalt.assets.ResourceUrn; + +import javax.inject.Inject; +import java.util.HashMap; +import java.util.Map; + +public class FactionsConfigs { + public final Map factionConfigs; + + @Inject + public FactionsConfigs(AssetHelper assetHelper) { + factionConfigs = new HashMap<>(); + + for (ResourceUrn resource : assetHelper.listAssets(Json.class, "factions")) { + JSONObject rootNode = Validator.getValidatedJSON(resource.toString(), "engine:schemaFactions"); + + Map> relations = new HashMap<>(); + + for (String factionName : rootNode.keySet()) { + ResourceUrn normalisedName = new ResourceUrn(factionName); + if (!factionConfigs.containsKey(normalisedName)) { + factionConfigs.put(normalisedName, FactionConfig.load(normalisedName, assetHelper.get(normalisedName, Json.class).get().getJsonValue())); + } + Map factionRelations = new HashMap<>(); + relations.put(normalisedName, new HashMap<>()); + JSONObject factionAttributes = rootNode.getJSONObject(factionName); + if (factionAttributes.has("relations")) { + JSONObject factionRelationsJSON = factionAttributes.getJSONObject("relations"); + for (String key : factionRelationsJSON.keySet()) { + factionRelations.put(new ResourceUrn(key), factionRelationsJSON.getInt(key)); + } + } + relations.put(normalisedName, factionRelations); + } + + for (Map.Entry> factionRelations : relations.entrySet()) { + Faction faction = factionConfigs.get(factionRelations.getKey()); + for (Map.Entry factionRelation : factionRelations.getValue().entrySet()) { + Faction otherFaction = factionConfigs.get(factionRelation.getKey()); + faction.setRelation(otherFaction, factionRelation.getValue()); + if (!otherFaction.isAwareOf(faction)) { + otherFaction.setRelation(faction, factionRelation.getValue()); + } + } + } + } + } +} diff --git a/engine/src/main/java/org/destinationsol/game/faction/ReputationEvent.java b/engine/src/main/java/org/destinationsol/game/faction/ReputationEvent.java new file mode 100644 index 000000000..248694d2f --- /dev/null +++ b/engine/src/main/java/org/destinationsol/game/faction/ReputationEvent.java @@ -0,0 +1,34 @@ +/* + * Copyright 2025 The Terasology Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.destinationsol.game.faction; + +/** + * An event that may affect relations between factions. + * @see DefaultReputationEvent DefaultReputationEvent + */ +public interface ReputationEvent { + /** + * Returns a string representation of this event. + * @return a string representation of this event. + */ + String toString(); + /** + * Returns the default impact on reputation this event will have in absence of a faction-specific value. + * @return the default impact on reputation this event will have in absence of a faction-specific value. + */ + int getDefaultReputationImpact(); +} diff --git a/engine/src/main/java/org/destinationsol/game/gun/GunMount.java b/engine/src/main/java/org/destinationsol/game/gun/GunMount.java index 179a2157c..7db91c957 100644 --- a/engine/src/main/java/org/destinationsol/game/gun/GunMount.java +++ b/engine/src/main/java/org/destinationsol/game/gun/GunMount.java @@ -19,11 +19,11 @@ import com.badlogic.gdx.math.Vector2; import org.destinationsol.Const; import org.destinationsol.common.SolMath; -import org.destinationsol.game.Faction; import org.destinationsol.game.SolGame; import org.destinationsol.game.SolObject; import org.destinationsol.game.drawables.Drawable; import org.destinationsol.game.drawables.DrawableManager; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.input.Shooter; import org.destinationsol.game.item.Gun; import org.destinationsol.game.item.ItemContainer; diff --git a/engine/src/main/java/org/destinationsol/game/gun/SolGun.java b/engine/src/main/java/org/destinationsol/game/gun/SolGun.java index 5b9a38558..629e14a0d 100644 --- a/engine/src/main/java/org/destinationsol/game/gun/SolGun.java +++ b/engine/src/main/java/org/destinationsol/game/gun/SolGun.java @@ -21,13 +21,13 @@ import org.destinationsol.common.SolColor; import org.destinationsol.common.SolMath; import org.destinationsol.common.SolRandom; -import org.destinationsol.game.Faction; import org.destinationsol.game.SolGame; import org.destinationsol.game.SolObject; import org.destinationsol.game.drawables.Drawable; import org.destinationsol.game.drawables.DrawableLevel; import org.destinationsol.game.drawables.RectSprite; import org.destinationsol.game.drawables.SpriteManager; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.item.Clip; import org.destinationsol.game.item.Gun; import org.destinationsol.game.item.ItemContainer; diff --git a/engine/src/main/java/org/destinationsol/game/input/AiPilot.java b/engine/src/main/java/org/destinationsol/game/input/AiPilot.java index eb9f25075..b096b9a59 100644 --- a/engine/src/main/java/org/destinationsol/game/input/AiPilot.java +++ b/engine/src/main/java/org/destinationsol/game/input/AiPilot.java @@ -18,8 +18,8 @@ import com.badlogic.gdx.math.Vector2; import org.destinationsol.common.SolMath; -import org.destinationsol.game.Faction; import org.destinationsol.game.SolGame; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.item.Engine; import org.destinationsol.game.item.Gun; import org.destinationsol.game.planet.Planet; @@ -199,18 +199,6 @@ public Faction getFaction() { return myFaction; } - @Override - public void stringToFaction(String faction) { - Map factionMap = new HashMap<>(); - if (faction.equals("laani")) { - factionMap.put(faction, Faction.LAANI); - } - if (faction.equals("ehar")) { - factionMap.put(faction, Faction.EHAR); - } - myFaction = factionMap.get(faction); - } - @Override public boolean shootsAtObstacles() { return myShootAtObstacles; diff --git a/engine/src/main/java/org/destinationsol/game/input/Pilot.java b/engine/src/main/java/org/destinationsol/game/input/Pilot.java index 5cb1f571e..9348c2e12 100644 --- a/engine/src/main/java/org/destinationsol/game/input/Pilot.java +++ b/engine/src/main/java/org/destinationsol/game/input/Pilot.java @@ -16,8 +16,8 @@ package org.destinationsol.game.input; -import org.destinationsol.game.Faction; import org.destinationsol.game.SolGame; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.ship.FarShip; import org.destinationsol.game.ship.SolShip; @@ -40,8 +40,6 @@ public interface Pilot { Faction getFaction(); - void stringToFaction(String faction); - boolean shootsAtObstacles(); float getDetectionDist(); diff --git a/engine/src/main/java/org/destinationsol/game/input/UiControlledPilot.java b/engine/src/main/java/org/destinationsol/game/input/UiControlledPilot.java index 01ce59fa4..7100ac3a8 100644 --- a/engine/src/main/java/org/destinationsol/game/input/UiControlledPilot.java +++ b/engine/src/main/java/org/destinationsol/game/input/UiControlledPilot.java @@ -17,17 +17,18 @@ package org.destinationsol.game.input; import org.destinationsol.Const; -import org.destinationsol.game.Faction; import org.destinationsol.game.SolGame; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.screens.ShipUiControl; import org.destinationsol.game.ship.FarShip; import org.destinationsol.game.ship.SolShip; public class UiControlledPilot implements Pilot { - + private final Faction faction; private final ShipUiControl uiControls; - public UiControlledPilot(ShipUiControl controls) { + public UiControlledPilot(Faction faction, ShipUiControl controls) { + this.faction = faction; uiControls = controls; } @@ -72,12 +73,7 @@ public boolean isAbility() { @Override public Faction getFaction() { - return Faction.LAANI; - } - - @Override - public void stringToFaction(String faction) { - // TODO Create values outside of laani and ehar, making this necessary + return faction; } @Override diff --git a/engine/src/main/java/org/destinationsol/game/maze/MazeBuilder.java b/engine/src/main/java/org/destinationsol/game/maze/MazeBuilder.java index c328d6a01..a6acce2ed 100644 --- a/engine/src/main/java/org/destinationsol/game/maze/MazeBuilder.java +++ b/engine/src/main/java/org/destinationsol/game/maze/MazeBuilder.java @@ -21,7 +21,6 @@ import org.destinationsol.Const; import org.destinationsol.common.SolMath; import org.destinationsol.common.SolRandom; -import org.destinationsol.game.Faction; import org.destinationsol.game.ShipConfig; import org.destinationsol.game.SolGame; import org.destinationsol.game.input.AiPilot; @@ -167,7 +166,7 @@ private void buildEnemy(Vector2 position, SolGame game, ShipConfig e, boolean in if (inner) { viewDist = TILE_SZ * 1.25f; } - Pilot pilot = new AiPilot(new StillGuard(position, game, e), false, Faction.EHAR, true, null, viewDist); + Pilot pilot = new AiPilot(new StillGuard(position, game, e), false, game.getFactionMan().getBuilderForHull(e.hull), true, null, viewDist); int money = e.money; FarShip s = sb.buildNewFar(game, position, new Vector2(), angle, 0, pilot, e.items, e.hull, null, false, money, null, true); game.getObjectManager().addFarObjNow(s); diff --git a/engine/src/main/java/org/destinationsol/game/planet/PlanetObjectsBuilder.java b/engine/src/main/java/org/destinationsol/game/planet/PlanetObjectsBuilder.java index 6e41d73d9..ea9149194 100644 --- a/engine/src/main/java/org/destinationsol/game/planet/PlanetObjectsBuilder.java +++ b/engine/src/main/java/org/destinationsol/game/planet/PlanetObjectsBuilder.java @@ -25,13 +25,13 @@ import org.destinationsol.common.SolMath; import org.destinationsol.common.SolRandom; import org.destinationsol.game.DebugOptions; -import org.destinationsol.game.Faction; import org.destinationsol.game.ShipConfig; import org.destinationsol.game.SolGame; import org.destinationsol.game.drawables.Drawable; import org.destinationsol.game.drawables.DrawableLevel; import org.destinationsol.game.drawables.RectSprite; import org.destinationsol.game.drawables.SpriteManager; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.input.AiPilot; import org.destinationsol.game.input.OrbiterDestProvider; import org.destinationsol.game.input.Pilot; @@ -104,7 +104,7 @@ private void createShips(SolGame game, Planet planet) { private void buildStation(SolGame game, Planet planet, ConsumedAngles takenAngles) { ShipConfig stationConfig = planet.getConfig().stationConfig; if (stationConfig != null) { - buildGroundShip(game, planet, stationConfig, planet.getConfig().tradeConfig, Faction.LAANI, takenAngles, "Station"); + buildGroundShip(game, planet, stationConfig, planet.getConfig().tradeConfig, game.getFactionMan().getBuilderForHull(stationConfig.hull), takenAngles, "Station"); } } @@ -112,7 +112,7 @@ private void buildGroundEnemies(SolGame game, Planet planet, ConsumedAngles take for (ShipConfig groundEnemy : config.groundEnemies) { int count = (int) (groundEnemy.density * groundHeight); for (int i = 0; i < count; i++) { - buildGroundShip(game, planet, groundEnemy, null, Faction.EHAR, takenAngles, null); + buildGroundShip(game, planet, groundEnemy, null, game.getFactionMan().getBuilderForHull(groundEnemy.hull), takenAngles, null); } } } @@ -322,13 +322,13 @@ private void addDeco(SolGame game, float groundHeight, Vector2 planetPos, } private void buildGroundShip(SolGame game, Planet planet, ShipConfig shipConfig, TradeConfig tradeConfig, - Faction faction, ConsumedAngles takenAngles, String mapHint) { + Faction faction, ConsumedAngles takenAngles, String mapHint) { Vector2 position = game.getPlanetManager().findFlatPlace(game, planet, takenAngles, shipConfig.hull.getApproxRadius()); boolean goodSpot = true; boolean station = shipConfig.hull.getType() == HullConfig.Type.STATION; String shipItems = shipConfig.items; boolean hasRepairer; - hasRepairer = faction == Faction.LAANI; + hasRepairer = game.getHero().getFaction().getRelation(faction) >= 0; int money = shipConfig.money; float height = position.len(); float aboveGround; @@ -380,7 +380,7 @@ private FarShip buildOrbitEnemy(SolGame game, Planet planet, float heightPercent SolMath.free(directionToPlanet); OrbiterDestProvider destProvider = new OrbiterDestProvider(planet, height, clockwise); - Pilot provider = new AiPilot(destProvider, false, Faction.EHAR, true, null, detectionDistance); + Pilot provider = new AiPilot(destProvider, false, game.getFactionMan().getBuilderForHull(shipConfig.hull), true, null, detectionDistance); int money = shipConfig.money; diff --git a/engine/src/main/java/org/destinationsol/game/projectile/Projectile.java b/engine/src/main/java/org/destinationsol/game/projectile/Projectile.java index 4a8bfbd17..cbc8f8c55 100644 --- a/engine/src/main/java/org/destinationsol/game/projectile/Projectile.java +++ b/engine/src/main/java/org/destinationsol/game/projectile/Projectile.java @@ -25,7 +25,6 @@ import org.destinationsol.common.SolMath; import org.destinationsol.common.SolRandom; import org.destinationsol.game.DmgType; -import org.destinationsol.game.Faction; import org.destinationsol.game.FactionManager; import org.destinationsol.game.FarObject; import org.destinationsol.game.GameDrawer; @@ -35,6 +34,8 @@ import org.destinationsol.game.drawables.Drawable; import org.destinationsol.game.drawables.DrawableLevel; import org.destinationsol.game.drawables.SpriteManager; +import org.destinationsol.game.faction.DefaultReputationEvent; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.item.Shield; import org.destinationsol.game.particle.DSParticleEmitter; import org.destinationsol.game.particle.EffectConfig; @@ -216,7 +217,7 @@ private void collided(SolGame game) { game.getPartMan().blinks(position, game, config.collisionEffectBackground.size); } if (ship.getPilot().isPlayer() && obstacle instanceof SolShip) { - ship.changeDisposition(((SolShip) obstacle).getFactionID()); + game.getFactionMan().reportEvent(ship.getFaction(), ((SolShip) obstacle).getFaction(), DefaultReputationEvent.DAMAGED_SHIP); } game.getSoundManager().play(game, config.collisionSound, null, this); diff --git a/engine/src/main/java/org/destinationsol/game/screens/BorderDrawer.java b/engine/src/main/java/org/destinationsol/game/screens/BorderDrawer.java index 182736b96..44c236c5f 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/BorderDrawer.java +++ b/engine/src/main/java/org/destinationsol/game/screens/BorderDrawer.java @@ -23,7 +23,6 @@ import org.destinationsol.assets.Assets; import org.destinationsol.common.SolColor; import org.destinationsol.common.SolMath; -import org.destinationsol.game.Faction; import org.destinationsol.game.FactionManager; import org.destinationsol.game.HardnessCalc; import org.destinationsol.game.Hero; @@ -33,6 +32,7 @@ import org.destinationsol.game.SolObject; import org.destinationsol.game.StarPort; import org.destinationsol.game.context.Context; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.planet.Planet; import org.destinationsol.game.planet.PlanetManager; import org.destinationsol.game.planet.SolarSystem; diff --git a/engine/src/main/java/org/destinationsol/game/screens/BuyItemsScreen.java b/engine/src/main/java/org/destinationsol/game/screens/BuyItemsScreen.java index a17c3e846..7c4423154 100644 --- a/engine/src/main/java/org/destinationsol/game/screens/BuyItemsScreen.java +++ b/engine/src/main/java/org/destinationsol/game/screens/BuyItemsScreen.java @@ -17,9 +17,9 @@ package org.destinationsol.game.screens; import org.destinationsol.SolApplication; -import org.destinationsol.game.FactionInfo; import org.destinationsol.game.Hero; import org.destinationsol.game.SolGame; +import org.destinationsol.game.faction.DefaultReputationEvent; import org.destinationsol.game.item.ItemContainer; import org.destinationsol.game.item.SolItem; import org.destinationsol.game.ship.SolShip; @@ -54,7 +54,7 @@ public void initialise(SolApplication solApplication, InventoryScreen inventoryS target.getTradeContainer().getItems().remove(selectedItem); hero.getItemContainer().add(selectedItem); hero.setMoney(hero.getMoney() - selectedItem.getPrice()); - FactionInfo.setDisposition(target.getFactionID(), 1); + solApplication.getGame().getFactionMan().reportEvent(hero.getFaction(), target.getFaction(), DefaultReputationEvent.BOUGHT_ITEM); inventoryScreen.updateItemRows(); }); diff --git a/engine/src/main/java/org/destinationsol/game/ship/Door.java b/engine/src/main/java/org/destinationsol/game/ship/Door.java index 28a095f08..5311c084b 100644 --- a/engine/src/main/java/org/destinationsol/game/ship/Door.java +++ b/engine/src/main/java/org/destinationsol/game/ship/Door.java @@ -22,12 +22,12 @@ import com.badlogic.gdx.physics.box2d.joints.PrismaticJoint; import org.destinationsol.assets.sound.SpecialSounds; import org.destinationsol.common.SolMath; -import org.destinationsol.game.Faction; import org.destinationsol.game.FactionManager; import org.destinationsol.game.SolGame; import org.destinationsol.game.SolObject; import org.destinationsol.game.drawables.Drawable; import org.destinationsol.game.drawables.RectSprite; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.input.Pilot; import java.util.ArrayList; diff --git a/engine/src/main/java/org/destinationsol/game/ship/ForceBeacon.java b/engine/src/main/java/org/destinationsol/game/ship/ForceBeacon.java index da3fa64cb..a97ba7c79 100644 --- a/engine/src/main/java/org/destinationsol/game/ship/ForceBeacon.java +++ b/engine/src/main/java/org/destinationsol/game/ship/ForceBeacon.java @@ -19,10 +19,10 @@ import com.badlogic.gdx.math.Vector2; import org.destinationsol.assets.sound.SpecialSounds; import org.destinationsol.common.SolMath; -import org.destinationsol.game.Faction; import org.destinationsol.game.SolGame; import org.destinationsol.game.SolObject; import org.destinationsol.game.drawables.Drawable; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.input.Pilot; import org.destinationsol.game.particle.DSParticleEmitter; diff --git a/engine/src/main/java/org/destinationsol/game/ship/ShipBuilder.java b/engine/src/main/java/org/destinationsol/game/ship/ShipBuilder.java index 94a180e89..126938314 100644 --- a/engine/src/main/java/org/destinationsol/game/ship/ShipBuilder.java +++ b/engine/src/main/java/org/destinationsol/game/ship/ShipBuilder.java @@ -33,7 +33,6 @@ import org.destinationsol.common.SolMath; import org.destinationsol.common.SolRandom; import org.destinationsol.game.CollisionMeshLoader; -import org.destinationsol.game.Faction; import org.destinationsol.game.GameColors; import org.destinationsol.game.RemoveController; import org.destinationsol.game.SolGame; @@ -41,6 +40,7 @@ import org.destinationsol.game.drawables.DrawableLevel; import org.destinationsol.game.drawables.RectSprite; import org.destinationsol.game.drawables.SpriteManager; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.gun.GunMount; import org.destinationsol.game.input.Pilot; import org.destinationsol.game.item.Armor; @@ -154,15 +154,16 @@ public FarShip buildNewFar(SolGame game, Vector2 position, Vector2 velocity, flo } if (giveAmmo) { - addAbilityCharges(itemContainer, hullConfig, pilot); - addAmmo(itemContainer, g1, pilot); - addAmmo(itemContainer, g2, pilot); + boolean isPlayerAlly = game.getFactionMan().getPlayerFaction().getRelation(pilot.getFaction()) >= 0; + addAbilityCharges(isPlayerAlly, itemContainer, hullConfig, pilot); + addAmmo(isPlayerAlly, itemContainer, g1, pilot); + addAmmo(isPlayerAlly, itemContainer, g2, pilot); } return new FarShip(new Vector2(position), new Vector2(velocity), angle, rotationSpeed, pilot, itemContainer, hullConfig, hullConfig.getMaxLife(), g1, g2, removeController, ei, hasRepairer ? new ShipRepairer() : null, money, tc, shield, armor); } - private void addAmmo(ItemContainer ic, Gun g, Pilot pilot) { + private void addAmmo(boolean isPlayerAlly, ItemContainer ic, Gun g, Pilot pilot) { if (g == null) { return; } @@ -172,7 +173,7 @@ private void addAmmo(ItemContainer ic, Gun g, Pilot pilot) { return; } float clipUseTime = cc.size * gc.timeBetweenShots + gc.reloadTime; - float lifeTime = pilot.getFaction() == Faction.LAANI ? AVG_ALLY_LIFE_TIME : AVG_BATTLE_TIME; + float lifeTime = isPlayerAlly ? AVG_ALLY_LIFE_TIME : AVG_BATTLE_TIME; int count = 1 + (int) (lifeTime / clipUseTime) + SolRandom.randomInt(0, 2); for (int i = 0; i < count; i++) { if (ic.canAdd(cc.example)) { @@ -181,7 +182,7 @@ private void addAmmo(ItemContainer ic, Gun g, Pilot pilot) { } } - private void addAbilityCharges(ItemContainer ic, HullConfig hc, Pilot pilot) { + private void addAbilityCharges(boolean isPlayerAlly, ItemContainer ic, HullConfig hc, Pilot pilot) { if (hc.getAbility() != null) { SolItem ex = hc.getAbility().getChargeExample(); if (ex != null) { @@ -189,7 +190,7 @@ private void addAbilityCharges(ItemContainer ic, HullConfig hc, Pilot pilot) { if (pilot.isPlayer()) { count = 3; } else { - float lifeTime = pilot.getFaction() == Faction.LAANI ? AVG_ALLY_LIFE_TIME : AVG_BATTLE_TIME; + float lifeTime = isPlayerAlly ? AVG_ALLY_LIFE_TIME : AVG_BATTLE_TIME; count = (int) (lifeTime / hc.getAbility().getRechargeTime() * SolRandom.randomFloat(.3f, 1)); } for (int i = 0; i < count; i++) { diff --git a/engine/src/main/java/org/destinationsol/game/ship/SolShip.java b/engine/src/main/java/org/destinationsol/game/ship/SolShip.java index 0af4a0e68..aa77ba2b0 100644 --- a/engine/src/main/java/org/destinationsol/game/ship/SolShip.java +++ b/engine/src/main/java/org/destinationsol/game/ship/SolShip.java @@ -26,12 +26,12 @@ import org.destinationsol.common.SolRandom; import org.destinationsol.game.AbilityCommonConfig; import org.destinationsol.game.DmgType; -import org.destinationsol.game.FactionInfo; import org.destinationsol.game.Hero; import org.destinationsol.game.RemoveController; import org.destinationsol.game.SolGame; import org.destinationsol.game.SolObject; import org.destinationsol.game.drawables.Drawable; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.gun.GunMount; import org.destinationsol.game.input.Pilot; import org.destinationsol.game.item.Armor; @@ -62,8 +62,6 @@ public class SolShip implements SolObject { private static final float ENERGY_DMG_FACTOR = .7f; private boolean colliding; - private String factionName; - private int factionID; private final Pilot myPilot; private final ItemContainer myItemContainer; private final TradeContainer myTradeContainer; @@ -112,8 +110,6 @@ public SolShip(SolGame game, Pilot pilot, Hull hull, RemoveController removeCont if (myAbility != null) { myAbilityAwait = myAbility.getConfig().getRechargeTime(); } - factionID = FactionInfo.getFactionID(this); - factionName = FactionInfo.getFactionNames().get(factionID).toString(); } @Override @@ -241,12 +237,6 @@ public void update(SolGame game) { updateIdleTime(game); updateShield(game); - if (!isMerc && FactionInfo.getDisposition().get(factionID) < -5) { - getPilot().stringToFaction("ehar"); - } else { - getPilot().stringToFaction("laani"); - } - if (myArmor != null && !myItemContainer.contains(myArmor)) { myArmor = null; } @@ -689,15 +679,7 @@ public boolean isMerc() { return this.isMerc; } - public String getFactionName() { - return factionName; - } - - public int getFactionID() { - return factionID; - } - - public void changeDisposition(int id) { - FactionInfo.setDisposition(id, -1); + public Faction getFaction() { + return myPilot.getFaction(); } } diff --git a/engine/src/main/java/org/destinationsol/game/ship/Teleport.java b/engine/src/main/java/org/destinationsol/game/ship/Teleport.java index 66e972746..c5facf2b4 100644 --- a/engine/src/main/java/org/destinationsol/game/ship/Teleport.java +++ b/engine/src/main/java/org/destinationsol/game/ship/Teleport.java @@ -24,8 +24,8 @@ import org.destinationsol.common.SolMath; import org.destinationsol.common.SolRandom; import org.destinationsol.game.AbilityCommonConfig; -import org.destinationsol.game.Faction; import org.destinationsol.game.SolGame; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.item.ItemManager; import org.destinationsol.game.item.SolItem; import org.destinationsol.game.planet.Planet; diff --git a/engine/src/main/java/org/destinationsol/game/ship/hulls/Hull.java b/engine/src/main/java/org/destinationsol/game/ship/hulls/Hull.java index 410a15e2c..fd4474423 100644 --- a/engine/src/main/java/org/destinationsol/game/ship/hulls/Hull.java +++ b/engine/src/main/java/org/destinationsol/game/ship/hulls/Hull.java @@ -21,11 +21,11 @@ import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.Fixture; import org.destinationsol.common.SolMath; -import org.destinationsol.game.Faction; import org.destinationsol.game.SolCam; import org.destinationsol.game.SolGame; import org.destinationsol.game.drawables.Drawable; import org.destinationsol.game.drawables.DrawableManager; +import org.destinationsol.game.faction.Faction; import org.destinationsol.game.gun.GunMount; import org.destinationsol.game.input.Pilot; import org.destinationsol.game.item.Engine; diff --git a/engine/src/main/java/org/destinationsol/game/tutorial/steps/DestroySpawnedShipsStep.java b/engine/src/main/java/org/destinationsol/game/tutorial/steps/DestroySpawnedShipsStep.java index 4e1eeabf3..3e6fa42a8 100644 --- a/engine/src/main/java/org/destinationsol/game/tutorial/steps/DestroySpawnedShipsStep.java +++ b/engine/src/main/java/org/destinationsol/game/tutorial/steps/DestroySpawnedShipsStep.java @@ -20,7 +20,6 @@ import org.destinationsol.Const; import org.destinationsol.common.SolMath; import org.destinationsol.common.SolRandom; -import org.destinationsol.game.Faction; import org.destinationsol.game.Hero; import org.destinationsol.game.SolObject; import org.destinationsol.game.input.AiPilot; @@ -83,7 +82,7 @@ public void start() { } Guardian dp = new Guardian(game, enemyConfig, hero.getPilot(), hero.getPosition(), hero.getHull().getHullConfig(), 0); - Pilot pilot = new AiPilot(dp, true, Faction.EHAR, false, null, Const.AI_DET_DIST); + Pilot pilot = new AiPilot(dp, true, game.getFactionMan().getGenericEnemyFaction(), false, null, Const.AI_DET_DIST); int money = 60; FarShip enemy = game.getShipBuilder().buildNewFar(game, enemyPosition, null, 0, 0, pilot, items, diff --git a/engine/src/main/java/org/destinationsol/mercenary/MercenaryUtils.java b/engine/src/main/java/org/destinationsol/mercenary/MercenaryUtils.java index 7d917f8d4..f0193c06b 100644 --- a/engine/src/main/java/org/destinationsol/mercenary/MercenaryUtils.java +++ b/engine/src/main/java/org/destinationsol/mercenary/MercenaryUtils.java @@ -19,7 +19,6 @@ import org.destinationsol.Const; import org.destinationsol.common.SolMath; import org.destinationsol.common.SolRandom; -import org.destinationsol.game.Faction; import org.destinationsol.game.Hero; import org.destinationsol.game.ShipConfig; import org.destinationsol.game.SolGame; @@ -42,7 +41,7 @@ public class MercenaryUtils { public static boolean createMerc(SolGame game, Hero hero, MercItem mercItem) { ShipConfig config = mercItem.getConfig(); Guardian guardian = new Guardian(game, config.hull, hero.getPilot(), hero.getPosition(), hero.getHull().config, SolRandom.randomFloat(180)); - AiPilot pilot = new AiPilot(guardian, true, Faction.LAANI, false, "Merc", Const.AI_DET_DIST); + AiPilot pilot = new AiPilot(guardian, true, hero.getFaction(), false, "Merc", Const.AI_DET_DIST); Vector2 position = getPos(game, hero, config.hull); if (position == null) { return false; diff --git a/engine/src/main/resources/org/destinationsol/assets/configs/factions.json b/engine/src/main/resources/org/destinationsol/assets/configs/factions.json new file mode 100644 index 000000000..c902ad9dd --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/configs/factions.json @@ -0,0 +1,5 @@ +{ + "engine:player": {}, + "engine:laani": {}, + "engine:ehar": {} +} \ No newline at end of file diff --git a/engine/src/main/resources/org/destinationsol/assets/factions/ehar.json b/engine/src/main/resources/org/destinationsol/assets/factions/ehar.json new file mode 100644 index 000000000..2c57b8a89 --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/factions/ehar.json @@ -0,0 +1,7 @@ +{ + "name": "Ehar", + "description": "A generic all-bad faction. The forerunner to all hostile entities.", + "colour": "b0c4de", + "defaultDisposition": -100, + "shipDesigns": [] +} \ No newline at end of file diff --git a/engine/src/main/resources/org/destinationsol/assets/factions/laani.json b/engine/src/main/resources/org/destinationsol/assets/factions/laani.json new file mode 100644 index 000000000..41b70e139 --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/factions/laani.json @@ -0,0 +1,7 @@ +{ + "name": "Laani", + "description": "A generic all-good faction. The forerunner to all friendly entities.", + "colour": "b0c4de", + "defaultDisposition": 100, + "shipDesigns": [] +} \ No newline at end of file diff --git a/engine/src/main/resources/org/destinationsol/assets/factions/player.json b/engine/src/main/resources/org/destinationsol/assets/factions/player.json new file mode 100644 index 000000000..7b1181e79 --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/factions/player.json @@ -0,0 +1,7 @@ +{ + "name": "Player", + "description": "This is you.", + "colour": "b0c4de", + "defaultDisposition": 0, + "shipDesigns": [] +} \ No newline at end of file diff --git a/engine/src/main/resources/org/destinationsol/assets/schemas/schemaFaction.json b/engine/src/main/resources/org/destinationsol/assets/schemas/schemaFaction.json new file mode 100644 index 000000000..c9eae9600 --- /dev/null +++ b/engine/src/main/resources/org/destinationsol/assets/schemas/schemaFaction.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Configuration for an in-game faction and the members of the faction.", + "required": ["name", "description", "colour", "shipDesigns"], + "properties": { + "name": { + "type": "string", + "description": "The name of the faction." + }, + "description": { + "type": "string", + "description": "A string description the faction. This may include an overview of the faction's background." + }, + "colour": { + "type": "string", + "description": "Faction colours are hexadecimal, in the form RRGGBB(AA).", + "pattern": "^([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6})$" + }, + "shipDesigns": { + "type": "array", + "description": "A list of ship designs that can be produced by this faction.", + "items": { + "type": "string", + "description": "The ResourceUrn of a particular ship.", + "pattern": "^\\w+:\\w+$" + } + }, + "defaultDisposition": { + "type": "integer", + "description": "The default disposition that the faction has towards other unknown factions." + }, + "relations": { + "type": "object", + "additionalProperties": { "type": "integer" }, + "description": "Relations between factions." + } + } +} diff --git a/engine/src/main/resources/org/destinationsol/assets/schemas/schemaFactions.json b/engine/src/main/resources/org/destinationsol/assets/schemas/schemaFactions.json index 64519d114..45ab0bd3e 100644 --- a/engine/src/main/resources/org/destinationsol/assets/schemas/schemaFactions.json +++ b/engine/src/main/resources/org/destinationsol/assets/schemas/schemaFactions.json @@ -1,43 +1,5 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "description": "Configuration for in-game factions and the members of the factions.", - "properties": { - "factions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Faction names can be any non-blank string of ascii characters.", - "pattern": "^[ -~]+$" - }, - "color": { - "type": "string", - "description": "Faction colors are hexidecimal, in the form RRGGBB(AA).", - "pattern": "^([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6})$" - }, - "disposition": { - "type": "integer", - "description": "The opinion of the faction towards the player. Positive is friendly, negative is hostile. Faction will attack player when disposition < 0." - }, - "ships": { - "type": "array", - "description": "The list of ships in this faction.", - "items": { - "type": "string", - "description": "The string Id of this ship. Can be any sequence of basic alphanumeric characters without a space.", - "pattern": "^\\w+$" - } - } - }, - "required": [ - "name", - "color", - "disposition", - "ships" - ] - } - } - } + "additionalProperties": { "type": "object" } } diff --git a/modules/core/assets/configs/factions.json b/modules/core/assets/configs/factions.json index 5d547f6f0..89b931f43 100644 --- a/modules/core/assets/configs/factions.json +++ b/modules/core/assets/configs/factions.json @@ -1,73 +1,8 @@ { - "factions": [ - { - "name": "Imperial", - "color": "b0c4de", - "disposition": 50, - "ships": [ - "imperialBig", - "imperialCapital", - "imperialMedium", - "imperialSmall", - "imperialTiny", - "station" - ] - }, - { - "name": "Pirate", - "color": "DC143C", - "disposition": -100, - "ships": [ - "pirateMedium", - "pirateOrbiter", - "piratePlanetTurret", - "pirateSmall", - "pirateSpaceTurret", - "truck" - ] - }, - { - "name": "Techie", - "color": "169E10", - "disposition": -50, - "ships": [ - "techieOrbiter", - "techiePlanetTurret", - "techieSmall" - ] - }, - { - "name": "Miner", - "color": "FFFF33", - "disposition":0, - "ships": [ - "minerBoss", - "minerMedium", - "minerSmall", - "minerTurret" - ] - }, - { - "name": "Desert", - "color": "624A2E", - "disposition": -50, - "ships": [ - "desertBoss", - "desertMedium", - "desertPlanetTurret", - "desertSmall", - "desertSpaceTurret", - "desertOrbiter" - ] - }, - { - "name": "Trader", - "color": "006400", - "disposition": 50, - "ships": [ - "bus", - "drome" - ] - } - ] + "core:imperial": {}, + "core:pirate": {}, + "core:techie": {}, + "core:miner": {}, + "core:desert": {}, + "core:trader": {} } diff --git a/modules/core/assets/configs/systemsConfig.json b/modules/core/assets/configs/systemsConfig.json index be83747bb..4a2da2a2d 100644 --- a/modules/core/assets/configs/systemsConfig.json +++ b/modules/core/assets/configs/systemsConfig.json @@ -80,7 +80,7 @@ { "hull": "core:pirateMedium", - "items": "core:gun core:miner 0.25|core:lightArmor core:bigShield", + "items": "core:gun core:minerGun 0.25|core:lightArmor core:bigShield", "money": 200, "density": 0.0002 }, diff --git a/modules/core/assets/factions/desert.json b/modules/core/assets/factions/desert.json new file mode 100644 index 000000000..9024e4b50 --- /dev/null +++ b/modules/core/assets/factions/desert.json @@ -0,0 +1,14 @@ +{ + "name": "Desert", + "description": "Masters of camouflage. They also have a strange affinity for mazes.", + "colour": "624A2E", + "defaultDisposition": -50, + "shipDesigns": [ + "core:desertBoss", + "core:desertMedium", + "core:desertPlanetTurret", + "core:desertSmall", + "core:desertSpaceTurret", + "core:desertOrbiter" + ] +} \ No newline at end of file diff --git a/modules/core/assets/factions/imperial.json b/modules/core/assets/factions/imperial.json new file mode 100644 index 000000000..7e0ca8076 --- /dev/null +++ b/modules/core/assets/factions/imperial.json @@ -0,0 +1,14 @@ +{ + "name": "Imperial", + "description": "The Imperial faction has reigned for millennia. Their might is barely contested. Offend at your peril.", + "colour": "b0c4de", + "defaultDisposition": 50, + "shipDesigns": [ + "core:imperialBig", + "core:imperialCapital", + "core:imperialMedium", + "core:imperialSmall", + "core:imperialTiny", + "core:station" + ] +} \ No newline at end of file diff --git a/modules/core/assets/factions/miner.json b/modules/core/assets/factions/miner.json new file mode 100644 index 000000000..11a9f170d --- /dev/null +++ b/modules/core/assets/factions/miner.json @@ -0,0 +1,12 @@ +{ + "name": "Miner", + "description": "They break space rocks. Somebody's got to do it.", + "colour": "FFFF33", + "defaultDisposition": 0, + "shipDesigns": [ + "core:minerBoss", + "core:minerMedium", + "core:minerSmall", + "core:minerTurret" + ] +} \ No newline at end of file diff --git a/modules/core/assets/factions/pirate.json b/modules/core/assets/factions/pirate.json new file mode 100644 index 000000000..33974b436 --- /dev/null +++ b/modules/core/assets/factions/pirate.json @@ -0,0 +1,14 @@ +{ + "name": "Pirate", + "description": "Pirates. They steal stuff.", + "colour": "DC143C", + "defaultDisposition": -100, + "shipDesigns": [ + "core:pirateMedium", + "core:pirateOrbiter", + "core:piratePlanetTurret", + "core:pirateSmall", + "core:pirateSpaceTurret", + "core:truck" + ] +} \ No newline at end of file diff --git a/modules/core/assets/factions/techie.json b/modules/core/assets/factions/techie.json new file mode 100644 index 000000000..8d5b70041 --- /dev/null +++ b/modules/core/assets/factions/techie.json @@ -0,0 +1,11 @@ +{ + "name": "Techie", + "description": "Technical wizards. Can fix anything. Specialists in shield hacking technology.", + "colour": "169E10", + "defaultDisposition": -50, + "shipDesigns": [ + "core:techieOrbiter", + "core:techiePlanetTurret", + "core:techieSmall" + ] +} \ No newline at end of file diff --git a/modules/core/assets/factions/trader.json b/modules/core/assets/factions/trader.json new file mode 100644 index 000000000..1ea421a33 --- /dev/null +++ b/modules/core/assets/factions/trader.json @@ -0,0 +1,10 @@ +{ + "name": "Trader", + "description": "Merchants of the galaxy. Friends to all who can pay.", + "colour": "006400", + "defaultDisposition": 50, + "shipDesigns": [ + "core:bus", + "core:drome" + ] +} \ No newline at end of file diff --git a/modules/core/assets/items/guns/miner/miner.json b/modules/core/assets/items/guns/minerGun/minerGun.json similarity index 100% rename from modules/core/assets/items/guns/miner/miner.json rename to modules/core/assets/items/guns/minerGun/minerGun.json diff --git a/modules/core/assets/items/guns/miner/miner.png b/modules/core/assets/items/guns/minerGun/minerGun.png similarity index 100% rename from modules/core/assets/items/guns/miner/miner.png rename to modules/core/assets/items/guns/minerGun/minerGun.png diff --git a/modules/core/assets/items/guns/miner/minerIcon.png b/modules/core/assets/items/guns/minerGun/minerGunIcon.png similarity index 100% rename from modules/core/assets/items/guns/miner/minerIcon.png rename to modules/core/assets/items/guns/minerGun/minerGunIcon.png From 6fe1a6575ce3bb22ea9b489cef825f5ef6daf0fe Mon Sep 17 00:00:00 2001 From: BenjaminAmos <24301287+BenjaminAmos@users.noreply.github.com> Date: Fri, 10 Jan 2025 20:41:37 +0000 Subject: [PATCH 20/24] feat: make engines equippable (#704) --- .../java/org/destinationsol/game/SolGame.java | 16 +++++++ .../org/destinationsol/game/item/Engine.java | 42 +++++++++++++----- .../destinationsol/game/item/ItemManager.java | 4 +- .../game/item/SolItemTypes.java | 2 + .../destinationsol/game/ship/ShipBuilder.java | 15 ++++++- .../destinationsol/game/ship/ShipEngine.java | 4 +- .../org/destinationsol/game/ship/SolShip.java | 13 +++--- .../destinationsol/game/ship/hulls/Hull.java | 6 ++- .../game/tutorial/TutorialManager.java | 3 ++ .../ui/nui/screens/MainGameScreen.java | 7 +++ .../assets/textures/icons/iconEngine.png | Bin 0 -> 6590 bytes .../desertBigEngine/desertBigEngine.json | 1 + .../engines/desertEngine/desertEngine.json | 1 + .../imperialBigEngine/imperialBigEngine.json | 1 + .../imperialEngine/imperialEngine.json | 1 + .../engines/minerEngine/minerEngine.json | 1 + .../pirateBigEngine/pirateBigEngine.json | 1 + .../engines/pirateEngine/pirateEngine.json | 1 + .../engines/techieEngine/techieEngine.json | 1 + modules/core/assets/items/types.json | 6 +++ 20 files changed, 106 insertions(+), 20 deletions(-) create mode 100644 engine/src/main/resources/org/destinationsol/assets/textures/icons/iconEngine.png diff --git a/engine/src/main/java/org/destinationsol/game/SolGame.java b/engine/src/main/java/org/destinationsol/game/SolGame.java index f6fb6c94c..865b5a542 100644 --- a/engine/src/main/java/org/destinationsol/game/SolGame.java +++ b/engine/src/main/java/org/destinationsol/game/SolGame.java @@ -364,8 +364,16 @@ private void saveShip() { hull = hero.isTranscendent() ? hero.getTranscendentHero().getShip().getHullConfig() : hero.getHull().config; money = hero.getMoney(); items = new ArrayList<>(); + + SolItem defaultEngineItem = hull.getEngineConfig().exampleEngine; for (List group : hero.getItemContainer()) { for (SolItem i : group) { + if (i.isSame(defaultEngineItem)) { + // The default engine is always added to new ships to mimic previous behaviour. + // We do not want to save this engine, as it would otherwise be duplicated on reload. + continue; + } + items.add(0, i); } } @@ -618,8 +626,16 @@ public void setRespawnState() { respawnState.getRespawnItems().clear(); respawnState.getRespawnWaypoints().clear(); respawnState.setPlayerRespawned(true); + + SolItem defaultShipEngine = respawnState.getRespawnHull().getEngineConfig().exampleEngine; for (List group : hero.getItemContainer()) { for (SolItem item : group) { + if (item.isSame(defaultShipEngine)) { + // The default engine is always added to new ships to mimic previous behaviour. + // We do not want to save this engine, as it would otherwise be duplicated on respawn. + continue; + } + boolean equipped = hero.isTranscendent() || hero.maybeUnequip(this, item, false); if (equipped || SolRandom.test(.75f)) { respawnState.getRespawnItems().add(item); diff --git a/engine/src/main/java/org/destinationsol/game/item/Engine.java b/engine/src/main/java/org/destinationsol/game/item/Engine.java index 4368a2cd1..44ce285a3 100644 --- a/engine/src/main/java/org/destinationsol/game/item/Engine.java +++ b/engine/src/main/java/org/destinationsol/game/item/Engine.java @@ -16,17 +16,25 @@ package org.destinationsol.game.item; import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import org.destinationsol.assets.Assets; import org.destinationsol.assets.json.Validator; import org.destinationsol.game.SolGame; import org.json.JSONObject; public class Engine implements SolItem { + private static final TextureAtlas.AtlasRegion DEFAULT_ENGINE_ICON = Assets.getAtlasRegion("engine:iconEngine"); private final Config config; + private int equipped; private Engine(Config config) { this.config = config; } + private Engine(Config config, int equipped) { + this.config = config; + this.equipped = equipped; + } + @Override public String getDisplayName() { return config.displayName; @@ -60,7 +68,7 @@ public boolean isBig() { @Override public Engine copy() { - return new Engine(config); + return new Engine(config, equipped); } @Override @@ -75,22 +83,22 @@ public TextureAtlas.AtlasRegion getIcon(SolGame game) { @Override public SolItemType getItemType() { - return null; + return config.itemType; } @Override public String getCode() { - return null; + return config.code; } @Override public int isEquipped() { - return 0; + return this.equipped; } @Override public void setEquipped(int equipped) { - + this.equipped = equipped; } public static class Config { @@ -104,22 +112,28 @@ public static class Config { public final Engine exampleEngine; public final TextureAtlas.AtlasRegion icon; public final String code; + public final SolItemType itemType; private Config(String displayName, int price, String description, float rotationAcceleration, float acceleration, float maxRotationSpeed, boolean isBig, - TextureAtlas.AtlasRegion icon, String code) { + TextureAtlas.AtlasRegion icon, String code, ItemManager itemManager, SolItemType itemType) { this.displayName = displayName; this.price = price; - this.description = description; + this.description = description + "\n\n" + + "Acceleration: " + acceleration + " m/s^2\n" + + "Rotational Acceleration: " + rotationAcceleration + " rad/s^2\n" + + "Maximum Angular Velocity: " + maxRotationSpeed + " rad/s"; this.rotationAcceleration = rotationAcceleration; this.acceleration = acceleration; this.maxRotationSpeed = maxRotationSpeed; this.isBig = isBig; this.icon = icon; this.code = code; + this.itemType = itemType; this.exampleEngine = new Engine(this); + itemManager.registerItem(exampleEngine); } - public static Config load(String engineName) { + public static Config load(String engineName, ItemManager itemManager, SolItemTypes types) { JSONObject rootNode = Validator.getValidatedJSON(engineName, "engine:schemaEngine"); boolean isBig = rootNode.getBoolean("big"); @@ -127,9 +141,15 @@ public static Config load(String engineName) { float acceleration = (float) rootNode.optDouble("acceleration", 2f); float maxRotationSpeed = (float) rootNode.optDouble("maxRotationSpeed", isBig ? 40f : 230f); - // TODO: VAMPCAT: The icon / displayName was initially set to null. Is that correct? - - return new Config(null, 0, null, rotationAcceleration, acceleration, maxRotationSpeed, isBig, null, engineName); + TextureAtlas.AtlasRegion icon; + try { + icon = Assets.getAtlasRegion(engineName + "Icon"); + } catch (RuntimeException ignore) { + icon = DEFAULT_ENGINE_ICON; + } + return new Config(rootNode.optString("name", engineName), 0, + rootNode.optString("description", ""), rotationAcceleration, acceleration, + maxRotationSpeed, isBig, icon, engineName, itemManager, types.engine); } } } diff --git a/engine/src/main/java/org/destinationsol/game/item/ItemManager.java b/engine/src/main/java/org/destinationsol/game/item/ItemManager.java index 1b9787d9f..c49bf0758 100644 --- a/engine/src/main/java/org/destinationsol/game/item/ItemManager.java +++ b/engine/src/main/java/org/destinationsol/game/item/ItemManager.java @@ -155,6 +155,8 @@ public List parseItems(String items) { Clip.Config.load(itemName, this, myTypes); } else if (itemName.endsWith("Shield") || itemName.endsWith("shield")) { Shield.Config.load(itemName, this, soundManager, myTypes); + } else if (itemName.endsWith("Engine") || itemName.endsWith("engine")) { + Engine.Config.load(itemName, this, myTypes); } else { Gun.Config.load(itemName, this, soundManager, myTypes); } @@ -193,7 +195,7 @@ public SolItem getExample(String name) { } public Engine.Config getEngineConfig(String engineName) { - return engineConfigs.computeIfAbsent(engineName, engineConfig -> Engine.Config.load(engineConfig)); + return engineConfigs.computeIfAbsent(engineName, engineConfig -> Engine.Config.load(engineConfig, this, myTypes)); } public SolItem random() { diff --git a/engine/src/main/java/org/destinationsol/game/item/SolItemTypes.java b/engine/src/main/java/org/destinationsol/game/item/SolItemTypes.java index 6597deeb9..1a8cd472d 100644 --- a/engine/src/main/java/org/destinationsol/game/item/SolItemTypes.java +++ b/engine/src/main/java/org/destinationsol/game/item/SolItemTypes.java @@ -23,6 +23,7 @@ import org.json.JSONObject; public class SolItemTypes { + public final SolItemType engine; public final SolItemType clip; public final SolItemType shield; public final SolItemType armor; @@ -37,6 +38,7 @@ public class SolItemTypes { public SolItemTypes(OggSoundManager soundManager, GameColors cols) { JSONObject rootNode = Validator.getValidatedJSON("core:types", "engine:schemaTypes"); + engine = load(rootNode.getJSONObject("engine"), soundManager, cols); clip = load(rootNode.getJSONObject("clip"), soundManager, cols); shield = load(rootNode.getJSONObject("shield"), soundManager, cols); armor = load(rootNode.getJSONObject("armor"), soundManager, cols); diff --git a/engine/src/main/java/org/destinationsol/game/ship/ShipBuilder.java b/engine/src/main/java/org/destinationsol/game/ship/ShipBuilder.java index 126938314..3af3eb624 100644 --- a/engine/src/main/java/org/destinationsol/game/ship/ShipBuilder.java +++ b/engine/src/main/java/org/destinationsol/game/ship/ShipBuilder.java @@ -85,10 +85,16 @@ public FarShip buildNewFar(SolGame game, Vector2 position, Vector2 velocity, flo game.getItemMan().fillContainer(itemContainer, items); Engine.Config ec = hullConfig.getEngineConfig(); Engine ei = ec == null ? null : ec.exampleEngine.copy(); + // A ship's default engine is defined in its hull config. + // Engines are also regular items, so add the default to the ship's item container. + if (ei != null) { + itemContainer.add(ei); + } TradeContainer tc = tradeConfig == null ? null : new TradeContainer(tradeConfig); Gun g1 = null; Gun g2 = null; + Engine engine = ei; Shield shield = null; Armor armor = null; @@ -96,6 +102,12 @@ public FarShip buildNewFar(SolGame game, Vector2 position, Vector2 velocity, flo if (pilot.isPlayer()) { for (List group : itemContainer) { for (SolItem i : group) { + if (i instanceof Engine) { + if (i.isEquipped() > 0) { + engine = (Engine) i; + continue; + } + } if (i instanceof Shield) { if (i.isEquipped() > 0) { shield = (Shield) i; @@ -160,7 +172,7 @@ public FarShip buildNewFar(SolGame game, Vector2 position, Vector2 velocity, flo addAmmo(isPlayerAlly, itemContainer, g2, pilot); } return new FarShip(new Vector2(position), new Vector2(velocity), angle, rotationSpeed, pilot, itemContainer, hullConfig, hullConfig.getMaxLife(), - g1, g2, removeController, ei, hasRepairer ? new ShipRepairer() : null, money, tc, shield, armor); + g1, g2, removeController, engine, hasRepairer ? new ShipRepairer() : null, money, tc, shield, armor); } private void addAmmo(boolean isPlayerAlly, ItemContainer ic, Gun g, Pilot pilot) { @@ -216,6 +228,7 @@ public SolShip build(SolGame game, Vector2 position, Vector2 velocity, float ang hull.setParticleEmitters(game, ship); if (engine != null) { + engine.setEquipped(1); hull.setEngine(engine); } if (gun1 != null) { diff --git a/engine/src/main/java/org/destinationsol/game/ship/ShipEngine.java b/engine/src/main/java/org/destinationsol/game/ship/ShipEngine.java index 7d509431a..c348e922c 100644 --- a/engine/src/main/java/org/destinationsol/game/ship/ShipEngine.java +++ b/engine/src/main/java/org/destinationsol/game/ship/ShipEngine.java @@ -38,7 +38,9 @@ public ShipEngine(Engine engine) { public void update(float angle, SolGame game, Pilot provider, Body body, Vector2 velocity, boolean controlsEnabled, float mass, SolShip ship) { - + if (myItem.isEquipped() == 0) { + return; + } boolean working = applyInput(game, angle, provider, body, velocity, controlsEnabled, mass); game.getPartMan().updateAllHullEmittersOfType(ship, "engine", working); } diff --git a/engine/src/main/java/org/destinationsol/game/ship/SolShip.java b/engine/src/main/java/org/destinationsol/game/ship/SolShip.java index aa77ba2b0..c556a8dc4 100644 --- a/engine/src/main/java/org/destinationsol/game/ship/SolShip.java +++ b/engine/src/main/java/org/destinationsol/game/ship/SolShip.java @@ -110,6 +110,9 @@ public SolShip(SolGame game, Pilot pilot, Hull hull, RemoveController removeCont if (myAbility != null) { myAbilityAwait = myAbility.getConfig().getRechargeTime(); } + if (myHull.getEngine() != null && !myItemContainer.contains(myHull.getEngine())) { + myItemContainer.add(myHull.getEngine()); + } } @Override @@ -527,13 +530,11 @@ public boolean maybeEquip(SolGame game, SolItem item, boolean equip) { public boolean maybeEquip(SolGame game, SolItem item, boolean secondarySlot, boolean equip) { if (!secondarySlot) { if (item instanceof Engine) { - Gdx.app.log("SolShip", "maybeEquip called for an engine item, can't do that!"); - //throw new AssertionError("engine items not supported"); - Engine ei = (Engine) item; boolean ok = ei.isBig() == (myHull.config.getType() == HullConfig.Type.BIG); if (ok && equip) { myHull.setEngine(ei); + ei.setEquipped(1); } return ok; } @@ -581,9 +582,8 @@ public boolean maybeUnequip(SolGame game, SolItem item, boolean unequip) { public boolean maybeUnequip(SolGame game, SolItem item, boolean secondarySlot, boolean unequip) { if (!secondarySlot) { if (myHull.getEngine() == item) { - Gdx.app.log("SolShip", "maybeUnequip called for an engine item, can't do that!"); - //throw new AssertionError("engine items not supported"); if (unequip) { + item.setEquipped(0); myHull.setEngine(null); } return true; @@ -654,6 +654,9 @@ public boolean isControlsEnabled() { public void dropItem(SolGame game, SolItem item) { myItemContainer.remove(item); + if (item.isEquipped() > 0) { + maybeUnequip(game, item, true); + } throwLoot(game, item, false); } diff --git a/engine/src/main/java/org/destinationsol/game/ship/hulls/Hull.java b/engine/src/main/java/org/destinationsol/game/ship/hulls/Hull.java index fd4474423..d9a12a289 100644 --- a/engine/src/main/java/org/destinationsol/game/ship/hulls/Hull.java +++ b/engine/src/main/java/org/destinationsol/game/ship/hulls/Hull.java @@ -158,7 +158,11 @@ public void onRemove(SolGame game) { } public void setEngine(Engine engine) { - this.engine = new ShipEngine(engine); + if (engine != null) { + this.engine = new ShipEngine(engine); + } else { + this.engine = null; + } } public void setParticleEmitters(SolGame game, SolShip ship) { diff --git a/engine/src/main/java/org/destinationsol/game/tutorial/TutorialManager.java b/engine/src/main/java/org/destinationsol/game/tutorial/TutorialManager.java index a826ed6a9..a4615b129 100644 --- a/engine/src/main/java/org/destinationsol/game/tutorial/TutorialManager.java +++ b/engine/src/main/java/org/destinationsol/game/tutorial/TutorialManager.java @@ -21,6 +21,7 @@ import org.destinationsol.game.SolGame; import org.destinationsol.game.UpdateAwareSystem; import org.destinationsol.game.item.Armor; +import org.destinationsol.game.item.Engine; import org.destinationsol.game.item.Gun; import org.destinationsol.game.item.Shield; import org.destinationsol.game.item.SolItem; @@ -148,6 +149,7 @@ public void start() { } Map, String> itemTypesExplanations = new HashMap<>(); + itemTypesExplanations.put(Engine.class, "Engines allow your ship to move."); itemTypesExplanations.put(Gun.class, "You can mine asteroids and attack enemies with guns."); itemTypesExplanations.put(Armor.class, "Armour makes attacks less effective against you."); itemTypesExplanations.put(Shield.class, "Shields absorb energy-based projectiles until depleted."); @@ -177,6 +179,7 @@ public void start() { "Open your inventory (" + gameOptions.getKeyInventoryName() + ")." : "Open your inventory."), new ItemTypesExplanationStep(itemTypesExplanations, new Class[] { + Engine.class, Gun.class, Armor.class, Shield.class diff --git a/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java b/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java index 10078347a..4eb135913 100644 --- a/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java +++ b/engine/src/main/java/org/destinationsol/ui/nui/screens/MainGameScreen.java @@ -384,6 +384,13 @@ public Boolean get() { return hero.isNonTranscendent() && hero.getArmor() == null; } }); + addWarnDrawer("noEngine", warnColour, "No Engine", new ReadOnlyBinding() { + @Override + public Boolean get() { + Hero hero = solApplication.getGame().getHero(); + return hero.isNonTranscendent() && hero.getHull().getEngine() == null; + } + }); addWarnDrawer("enemyWarnDrawer", warnColour, "Dangerous Enemy", new ReadOnlyBinding() { @Override public Boolean get() { diff --git a/engine/src/main/resources/org/destinationsol/assets/textures/icons/iconEngine.png b/engine/src/main/resources/org/destinationsol/assets/textures/icons/iconEngine.png new file mode 100644 index 0000000000000000000000000000000000000000..43738dc091ed0f5ee0d8ab2db35ff01536d09c49 GIT binary patch literal 6590 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 QUuqy`Mh8g08F)nf8~d1wY5)KL literal 0 HcmV?d00001 diff --git a/modules/core/assets/items/engines/desertBigEngine/desertBigEngine.json b/modules/core/assets/items/engines/desertBigEngine/desertBigEngine.json index f299e2ba7..14ae64f3d 100644 --- a/modules/core/assets/items/engines/desertBigEngine/desertBigEngine.json +++ b/modules/core/assets/items/engines/desertBigEngine/desertBigEngine.json @@ -1,3 +1,4 @@ { + "name": "Large Desert Engine", "big": true } \ No newline at end of file diff --git a/modules/core/assets/items/engines/desertEngine/desertEngine.json b/modules/core/assets/items/engines/desertEngine/desertEngine.json index 9daf6299b..914006418 100644 --- a/modules/core/assets/items/engines/desertEngine/desertEngine.json +++ b/modules/core/assets/items/engines/desertEngine/desertEngine.json @@ -1,3 +1,4 @@ { + "name": "Desert Engine", "big": false } \ No newline at end of file diff --git a/modules/core/assets/items/engines/imperialBigEngine/imperialBigEngine.json b/modules/core/assets/items/engines/imperialBigEngine/imperialBigEngine.json index f299e2ba7..8b7e90c4b 100644 --- a/modules/core/assets/items/engines/imperialBigEngine/imperialBigEngine.json +++ b/modules/core/assets/items/engines/imperialBigEngine/imperialBigEngine.json @@ -1,3 +1,4 @@ { + "name": "Large Imperial Engine", "big": true } \ No newline at end of file diff --git a/modules/core/assets/items/engines/imperialEngine/imperialEngine.json b/modules/core/assets/items/engines/imperialEngine/imperialEngine.json index 9daf6299b..982bbbb23 100644 --- a/modules/core/assets/items/engines/imperialEngine/imperialEngine.json +++ b/modules/core/assets/items/engines/imperialEngine/imperialEngine.json @@ -1,3 +1,4 @@ { + "name": "Imperial Engine", "big": false } \ No newline at end of file diff --git a/modules/core/assets/items/engines/minerEngine/minerEngine.json b/modules/core/assets/items/engines/minerEngine/minerEngine.json index 9daf6299b..ff966bb34 100644 --- a/modules/core/assets/items/engines/minerEngine/minerEngine.json +++ b/modules/core/assets/items/engines/minerEngine/minerEngine.json @@ -1,3 +1,4 @@ { + "name": "Miner Engine", "big": false } \ No newline at end of file diff --git a/modules/core/assets/items/engines/pirateBigEngine/pirateBigEngine.json b/modules/core/assets/items/engines/pirateBigEngine/pirateBigEngine.json index f299e2ba7..d5461c3f6 100644 --- a/modules/core/assets/items/engines/pirateBigEngine/pirateBigEngine.json +++ b/modules/core/assets/items/engines/pirateBigEngine/pirateBigEngine.json @@ -1,3 +1,4 @@ { + "name": "Large Pirate Engine", "big": true } \ No newline at end of file diff --git a/modules/core/assets/items/engines/pirateEngine/pirateEngine.json b/modules/core/assets/items/engines/pirateEngine/pirateEngine.json index 9daf6299b..0c68aa935 100644 --- a/modules/core/assets/items/engines/pirateEngine/pirateEngine.json +++ b/modules/core/assets/items/engines/pirateEngine/pirateEngine.json @@ -1,3 +1,4 @@ { + "name": "Pirate Engine", "big": false } \ No newline at end of file diff --git a/modules/core/assets/items/engines/techieEngine/techieEngine.json b/modules/core/assets/items/engines/techieEngine/techieEngine.json index 9daf6299b..039d04b82 100644 --- a/modules/core/assets/items/engines/techieEngine/techieEngine.json +++ b/modules/core/assets/items/engines/techieEngine/techieEngine.json @@ -1,3 +1,4 @@ { + "name": "Techie Engine", "big": false } \ No newline at end of file diff --git a/modules/core/assets/items/types.json b/modules/core/assets/items/types.json index 954abe754..9fc4aacbf 100644 --- a/modules/core/assets/items/types.json +++ b/modules/core/assets/items/types.json @@ -1,4 +1,10 @@ { + "engine": { + "color": "hsb 0 100 50", + "pickUpSound": "core:otherPickUp", + "sz": 0.12 + }, + "clip": { "color": "hsb 0 100 50", "pickUpSound": "core:otherPickUp", From 0a65a3b864b99eafd976e8e3caf2b0a82503395f Mon Sep 17 00:00:00 2001 From: BenjaminAmos <24301287+BenjaminAmos@users.noreply.github.com> Date: Sat, 22 Feb 2025 19:45:01 +0000 Subject: [PATCH 21/24] fix: fix animated sprites being loaded as normal sprites (#708) --- engine/src/main/java/org/destinationsol/assets/Assets.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/main/java/org/destinationsol/assets/Assets.java b/engine/src/main/java/org/destinationsol/assets/Assets.java index 92ceb4d8b..51ac3eacf 100644 --- a/engine/src/main/java/org/destinationsol/assets/Assets.java +++ b/engine/src/main/java/org/destinationsol/assets/Assets.java @@ -225,7 +225,7 @@ public static Animation getAnimation(String texturePat } String animationPath = texturePath + "Animation"; - if (!assetHelper.get(new ResourceUrn(animationPath), DSTexture.class).isPresent()) { + if (!assetHelper.get(new ResourceUrn(animationPath), Json.class).isPresent()) { return new Animation<>(Float.MAX_VALUE, getAtlasRegion(texturePath)); } From f68940da19fc10bb663b0dc07a2e63c0cb772fda Mon Sep 17 00:00:00 2001 From: BenjaminAmos <24301287+BenjaminAmos@users.noreply.github.com> Date: Mon, 31 Mar 2025 10:15:25 +0100 Subject: [PATCH 22/24] fix: constantAllies and constantEnemies are now always friendly or hostile respectively (#709) --- .../src/main/java/org/destinationsol/game/GalaxyFiller.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/src/main/java/org/destinationsol/game/GalaxyFiller.java b/engine/src/main/java/org/destinationsol/game/GalaxyFiller.java index b78984f44..3259ba75a 100644 --- a/engine/src/main/java/org/destinationsol/game/GalaxyFiller.java +++ b/engine/src/main/java/org/destinationsol/game/GalaxyFiller.java @@ -162,7 +162,7 @@ public void fill(SolGame game, HullConfigManager hullConfigManager, ItemManager int count = (int) (shipConfig.density); for (int i = 0; i < count; i++) { // TODO: Select an appropriate ally faction based on the player faction. - build(game, shipConfig, game.getFactionMan().getBuilderForHull(shipConfig.hull), false, system, angles); + build(game, shipConfig, game.getFactionMan().getGenericAllyFaction(), false, system, angles); } } @@ -170,7 +170,7 @@ public void fill(SolGame game, HullConfigManager hullConfigManager, ItemManager int count = (int) (shipConfig.density); for (int i = 0; i < count; i++) { // TODO: Select an appropriate enemy faction based on the player faction. - build(game, shipConfig, game.getFactionMan().getBuilderForHull(mainStationCfg.hull), false, system, angles); + build(game, shipConfig, game.getFactionMan().getGenericEnemyFaction(), false, system, angles); } } From 52b23c412b6f84753d855f51e81a785753a98a52 Mon Sep 17 00:00:00 2001 From: BenjaminAmos <24301287+BenjaminAmos@users.noreply.github.com> Date: Sun, 6 Apr 2025 10:55:57 +0100 Subject: [PATCH 23/24] fix: fix default faction dispositions not being applied (#710) --- .../destinationsol/game/FactionManager.java | 2 +- .../game/faction/FactionsConfigs.java | 30 +++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/engine/src/main/java/org/destinationsol/game/FactionManager.java b/engine/src/main/java/org/destinationsol/game/FactionManager.java index 45ccc0cce..053aef310 100644 --- a/engine/src/main/java/org/destinationsol/game/FactionManager.java +++ b/engine/src/main/java/org/destinationsol/game/FactionManager.java @@ -217,7 +217,7 @@ public boolean areEnemies(SolShip s1, SolShip s2) { * @return true, if f1 and f2 are enemies, otherwise false. */ public boolean areEnemies(Faction f1, Faction f2) { - return f1 != null && f2 != null && f1.getRelation(f2) < 0; + return f1 != null && f2 != null && (f1.getRelation(f2) < 0 || f2.getRelation(f1) < 0); } private static class MyRayBack implements RayCastCallback { diff --git a/engine/src/main/java/org/destinationsol/game/faction/FactionsConfigs.java b/engine/src/main/java/org/destinationsol/game/faction/FactionsConfigs.java index 019fbc7b1..0921bc7a0 100644 --- a/engine/src/main/java/org/destinationsol/game/faction/FactionsConfigs.java +++ b/engine/src/main/java/org/destinationsol/game/faction/FactionsConfigs.java @@ -60,8 +60,34 @@ public FactionsConfigs(AssetHelper assetHelper) { for (Map.Entry factionRelation : factionRelations.getValue().entrySet()) { Faction otherFaction = factionConfigs.get(factionRelation.getKey()); faction.setRelation(otherFaction, factionRelation.getValue()); - if (!otherFaction.isAwareOf(faction)) { - otherFaction.setRelation(faction, factionRelation.getValue()); + } + } + + for (Faction faction : factionConfigs.values()) { + for (Faction otherFaction : factionConfigs.values()) { + if (faction.isAwareOf(otherFaction) && otherFaction.isAwareOf(faction)) { + // Asymmetric relationships are explicitly allowed. + continue; + } + + if (faction.isAwareOf(otherFaction) && !otherFaction.isAwareOf(faction)) { + otherFaction.setRelation(faction, faction.getRelation(otherFaction)); + } else if (!faction.isAwareOf(otherFaction) && otherFaction.isAwareOf(faction)) { + faction.setRelation(otherFaction, otherFaction.getRelation(faction)); + } else { + int factionRelation = faction.getRelation(otherFaction); + int otherFactionRelation = otherFaction.getRelation(faction); + + // The simplified rules of uncertain Destination Sol diplomacy: + // - If both are friendly, the stronger positivity will prevail. + // - If both are hostile, the stronger hostility will prevail. + // - If your enemy is hostile to you, you must be hostile to your enemy. + // - Neutrality is considered friendly. + int relation = (factionRelation >= 0 && otherFactionRelation >= 0) ? + Math.max(factionRelation, otherFactionRelation) : + Math.min(factionRelation, otherFactionRelation); + faction.setRelation(otherFaction, relation); + otherFaction.setRelation(faction, relation); } } } From 4c0607310da634977a858a67fb85cce9878164dd Mon Sep 17 00:00:00 2001 From: BenjaminAmos <24301287+BenjaminAmos@users.noreply.github.com> Date: Tue, 15 Jul 2025 10:34:24 +0100 Subject: [PATCH 24/24] doc: use light logo in README with dark themes --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a6ab8cc6..cac93b6a2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,10 @@ -

Destination Sol

+

+ + + + Destination Sol + +

[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/MovingBlocks/DestinationSol) [![Discord](https://img.shields.io/discord/270264625419911192.svg?label=discord)](http://discord.gg/Terasology)