From 9cf829c69497e07fd71b50a63c0b62e080881842 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 4 Sep 2025 10:27:12 -0400 Subject: [PATCH 01/62] v3.2.4: fixed dynamic island detection on iOS --- .../shatteredpixeldungeon/ios/IOSPlatformSupport.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java b/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java index 53af1f355..0dfbbb885 100644 --- a/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java +++ b/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java @@ -77,8 +77,7 @@ public class IOSPlatformSupport extends PlatformSupport { insets.left = insets.top = insets.right = 0; } else if (level == INSET_LRG){ //Dynamic Island counts as a 'small cutout', we have to use status bar height to get it =I - CGRect statusBarFrame = UIApplication.getSharedApplication().getStatusBarFrame(); - double statusBarHeight = Math.min(statusBarFrame.getWidth(), statusBarFrame.getHeight()); + double statusBarHeight = insets.top / Gdx.graphics.getBackBufferScale(); if (statusBarHeight >= 51){ //magic number BS for larger status bar caused by island insets.left = insets.top = insets.right = 0; } From dacac930a52418b7103cb194dc35d2f7cfd3f61e Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Fri, 5 Sep 2025 13:18:13 -0400 Subject: [PATCH 02/62] v3.2.4: improved large vs. small cutout detection on Android --- .../android/AndroidPlatformSupport.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java index 72c0d10b9..29942aac6 100644 --- a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java +++ b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java @@ -91,8 +91,9 @@ public class AndroidPlatformSupport extends PlatformSupport { int screenSize = Game.width * Game.height; for (Rect r : cutout.getBoundingRects()){ int cutoutSize = Math.abs(r.height() * r.width()); - //display cutouts are considered large if they take up more than 0.5% of the screen - if (cutoutSize*200 >= screenSize){ + //display cutouts are considered large if they take up more than 0.605% of the screen + //in reality we want less than about 0.5%, but some cutouts over-report their size + if (cutoutSize*165 >= screenSize){ largeCutout = true; } } From 21f2753e970cc538e7029afa2d3ebdba4fe325f3 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Fri, 5 Sep 2025 13:24:52 -0400 Subject: [PATCH 03/62] v3.2.4: overhauled status and menu bar to better support display cutouts --- core/src/main/assets/interfaces/menu_pane.png | Bin 152 -> 233 bytes .../main/assets/interfaces/status_pane.png | Bin 1045 -> 1051 bytes .../scenes/GameScene.java | 12 ++-- .../shatteredpixeldungeon/ui/MenuPane.java | 59 +++++++++++------- .../shatteredpixeldungeon/ui/StatusPane.java | 42 +++++++------ 5 files changed, 70 insertions(+), 43 deletions(-) diff --git a/core/src/main/assets/interfaces/menu_pane.png b/core/src/main/assets/interfaces/menu_pane.png index b28ddc181fdb220d92b0ffec02d4449054d32522..83666e69360ad57e106d92858e8bc64ac3936a00 100644 GIT binary patch delta 218 zcmbQi_>ysgc)bD(GXn!dV@UdOAf+DQ6XFV_Gjb9`BLfyMo2sg=sG_EzrK75;t)iqN zSKUxtT#?g1xuvq!?LGO?1!qWE+?~7-#Z#v9X6RUfsfC()fufgt51eEyYeliYH)gU{Hv{*;s~$Tm~}p-pmI1 Ofx*+&&t;ucLK6Ta>_Jrk delta 137 zcmV;40CxZB0hj@h7k>~41^@s6cL04^0001ANkl%(_-m_=rTtL#Lpm+zBlMUG(+;oMQ z1vX5IQ}(|LeDmY95DpI;G6d!o62~;+HADj8aKuS;o3%69*P0J0D(SEpU4C5nU^E@jJi=!d&2Xy5i8E>l1+T zUCagaz=1a`$_s$iVu-JRfL; z3A|Hrz=tdLDu*$h{l!a!H9s<4lImCbq)$oo3%$~3r1_bC>2rUQ{6x?61*v|dPx_KX zKhP_EMVjyFm%b*+cl1o(aNt`86~wr50DfeFk>!9KkOOi+4#)vHK)l3bPDmW%x58RL zIN~G>qzxD_kThU0kTzg2kThU0kTzg2kTzg|@%ICHz>ouSz*`>hrlRFX3AlF_|4kAC zM8VFpV2l8!=j?y{(bVGv6z;z}+~R4Z0YfPFces`T!5s+*jr|>Nbie?#@7?|mH#T4Z z+V^gMhuaPqBEsU@{tmYtFhs53w@=u)!ivsrryO(tezk2MB}}N;^8Z)`;FuA&QO%6@ zQJ4rYUlaFURnOP7kCwlJk2%zyKD*DX4!b2T;VE$n~VHwDPM?sCM yCDse`g871FAOr3N)vKmhAIuZx8|Icjy({%sXe*fKw|KgJW=bZoRq>~K+AAjDN^3{m)%yaU_Y4X5a^0q|ss~rLw zOCbON010$bPE-H?|NsC0|Nj6}Pk0gl00NjvL_t(|0qxm|N-Redhw<;6IyH6(3}$%) zB@2*%Z(#PYhb3%zLRn=I2z&Mb1BjCd$y2B>gT`q)X>1x8OLGhQOaZrkY$XHqM}fui zr++k+vJ@dai!cFw=}!wrKuK$7t&yv1BRLFaLYiqCg)E(}BKZMVr0jPaG6TAH70C{; zn|DdMo^LR++^r({0l@+(7LdD^9Ji5N20BwxX3AzomPj@OH6_KAK*X7W1|=mZM0OFN zN{T8_Dxe0`fErK(YQQBu8lZI#SbivM`G0e*4CGiOJ{W`k5)o7i9X0Ny(Sw`H^YKS7iBtiOJXF>CyM>SW}o$SPiHFHJ}F6 zfErK(YJgFg2rt>go6!ZH(+1rA&wP)IjQJiH8S}l5jQQS0#(eK1W4`y1G2a7a=li;v z)qomM1DZ9Xy%GVdz@QD32nZNG?tf=(kpSKp7u+%d{tNCn-zVtO{1@DDzE9BDB^KOW z&G*B-`!BfZ`JUn4{TJMEzE6k;OaBFTobOXE;QWXl3;+2(Wo6@+R{ 0 ? 0 : 1)); + menu.setPos( uiCamera.width-MenuPane.WIDTH-insets.right, insets.top); add(menu); + //TODO buff indicator and boss HP need to be moved down slightly on iOS devices with dynamic island + //TODO buff indicator probably cut off on some Android devices, get display cutout size and check? + //TODO need to reject inputs on the bars (just turn then into hotareas? + //TODO make top bar transparent and add 1px of top status and menu bar to it? + status = new StatusPane( SPDSettings.interfaceSize() > 0 ); status.camera = uiCamera; status.setRect(insets.left, uiSize > 0 ? uiCamera.height-39-insets.bottom : insets.top, uiCamera.width - insets.left - insets.right, 0 ); @@ -384,7 +388,7 @@ public class GameScene extends PixelScene { boss = new BossHealthBar(); boss.camera = uiCamera; - boss.setPos( insets.left + 6 + (uiCamera.width - insets.left - insets.right - boss.width())/2, insets.top + 20); + boss.setPos( insets.left + 6 + (uiCamera.width - insets.left - insets.right - boss.width())/2, insets.top + 21); add(boss); resume = new ResumeIndicator(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java index 9d89dda48..829f36118 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java @@ -42,8 +42,10 @@ import com.watabou.input.GameAction; import com.watabou.noosa.BitmapText; import com.watabou.noosa.Game; import com.watabou.noosa.Image; +import com.watabou.noosa.NinePatch; import com.watabou.noosa.audio.Sample; import com.watabou.noosa.ui.Component; +import com.watabou.utils.DeviceCompat; public class MenuPane extends Component { @@ -63,18 +65,26 @@ public class MenuPane extends Component { private Toolbar.PickedUpItem pickedUp; private BitmapText version; + private NinePatch versionOverflowBG; private DangerIndicator danger; - public static final int WIDTH = 32; + public static final int WIDTH = 31; @Override protected void createChildren() { super.createChildren(); - bg = new Image(Assets.Interfaces.MENU); + bg = new Image(Assets.Interfaces.MENU, 1, 0, 31, 20); add(bg); + versionOverflowBG = new NinePatch(bg.texture, 1, 23, 6, 7, 3, 0, 2, 0); + add(versionOverflowBG); + + version = new BitmapText( "v" + Game.version , PixelScene.pixelFont); + version.alpha( 0.5f ); + add(version); + depthIcon = Icons.get(Dungeon.level.feeling); add(depthIcon); @@ -137,10 +147,6 @@ public class MenuPane extends Component { btnMenu = new MenuButton(); add( btnMenu ); - version = new BitmapText( "v" + Game.version, PixelScene.pixelFont); - version.alpha( 0.5f ); - add(version); - danger = new DangerIndicator(); add( danger ); @@ -154,13 +160,31 @@ public class MenuPane extends Component { bg.x = x; bg.y = y; + version.scale.set(PixelScene.align(0.5f)); + version.measure(); + + float rightMargin = DeviceCompat.isDesktop() ? 1 : 8; + if (DeviceCompat.isDebug()) rightMargin = 1; //don't care about hiding 'indev' + float overFlow = version.width()-(bg.width()-4-rightMargin); + if (overFlow >= 1){ + version.x = x + 2 - overFlow; + versionOverflowBG.size(overFlow+3, 7); + versionOverflowBG.x = version.x-3; + versionOverflowBG.y = y; + } else { + version.x = x + 3; + versionOverflowBG.visible = false; + } + version.y = y + 2 - (version.baseLine()*version.scale.y)/2f; + version.y -= .001f; + PixelScene.align(version); + btnMenu.setPos( x + WIDTH - btnMenu.width(), y ); btnJournal.setPos( btnMenu.left() - btnJournal.width() + 2, y ); depthIcon.x = btnJournal.left() - 7 + (7 - depthIcon.width())/2f - 0.1f; - depthIcon.y = y + 1; - if (SPDSettings.interfaceSize() == 0) depthIcon.y++; + depthIcon.y = y+7; PixelScene.align(depthIcon); depthText.scale.set(PixelScene.align(0.67f)); @@ -172,8 +196,7 @@ public class MenuPane extends Component { if (challengeIcon != null){ challengeIcon.x = btnJournal.left() - 14 + (7 - challengeIcon.width())/2f - 0.1f; - challengeIcon.y = y + 1; - if (SPDSettings.interfaceSize() == 0) challengeIcon.y++; + challengeIcon.y = depthIcon.y; PixelScene.align(challengeIcon); challengeText.scale.set(PixelScene.align(0.67f)); @@ -184,13 +207,7 @@ public class MenuPane extends Component { challengeButton.setRect(challengeIcon.x, challengeIcon.y, challengeIcon.width(), challengeIcon.height() + challengeText.height()); } - version.scale.set(PixelScene.align(0.5f)); - version.measure(); - version.x = x + WIDTH - version.width(); - version.y = y + bg.height() + (3 - version.baseLine()); - PixelScene.align(version); - - danger.setPos( x + WIDTH - danger.width(), y + bg.height + 3 ); + danger.setPos( x + WIDTH - danger.width(), y + bg.height + 1 ); } public void pickup(Item item, int cell) { @@ -222,7 +239,7 @@ public class MenuPane extends Component { super(); width = bg.width + 4; - height = bg.height + 4; + height = bg.height + 9; } @Override @@ -250,7 +267,7 @@ public class MenuPane extends Component { super.layout(); bg.x = x + 2; - bg.y = y + 2; + bg.y = y + 7; journalIcon.x = bg.x + (bg.width() - journalIcon.width())/2f; journalIcon.y = bg.y + (bg.height() - journalIcon.height())/2f; @@ -355,7 +372,7 @@ public class MenuPane extends Component { super(); width = image.width + 4; - height = image.height + 4; + height = image.height + 9; } @Override @@ -371,7 +388,7 @@ public class MenuPane extends Component { super.layout(); image.x = x + 2; - image.y = y + 2; + image.y = y + 7; } @Override diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java index 853263ec8..ef151ec3f 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java @@ -86,7 +86,8 @@ public class StatusPane extends Component { this.large = large; if (large) bg = new NinePatch( asset, 0, 64, 41, 39, 33, 0, 4, 0 ); - else bg = new NinePatch( asset, 0, 0, 128, 36, 85, 0, 45, 0 ); + //right part is transparent now so Ninepatching doesn't actually do anything + else bg = new NinePatch( asset, 0, 0, 128, 35, 85, 0, 45, 0 ); add( bg ); heroInfo = new Button(){ @@ -143,15 +144,13 @@ public class StatusPane extends Component { add(heroInfoOnBar); if (large) exp = new Image(asset, 0, 121, 128, 7); - else exp = new Image(asset, 0, 44, 16, 1); + else exp = new Image(asset, 0, 44, 17, 4); add( exp ); - if (large){ - expText = new BitmapText(PixelScene.pixelFont); - expText.hardlight( 0xFFFFAA ); - expText.alpha(0.6f); - add(expText); - } + expText = new BitmapText(PixelScene.pixelFont); + expText.hardlight( 0xFFFFAA ); + expText.alpha(0.6f); + add(expText); level = new BitmapText( PixelScene.pixelFont); level.hardlight( 0xFFFFAA ); @@ -171,7 +170,7 @@ public class StatusPane extends Component { @Override protected void layout() { - height = large ? 39 : 32; + height = large ? 39 : 35; bg.x = x; bg.y = y; @@ -179,10 +178,10 @@ public class StatusPane extends Component { else bg.size( width, bg.height ); avatar.x = bg.x - avatar.width / 2f + 15; - avatar.y = bg.y - avatar.height / 2f + (large ? 15 : 16); + avatar.y = bg.y - avatar.height / 2f + (large ? 15 : 14); PixelScene.align(avatar); - heroInfo.setRect( x, y+(large ? 0 : 1), 30, large ? 40 : 30 ); + heroInfo.setRect( x, y, 30, large ? 40 : 35 ); compass.x = avatar.x + avatar.width / 2f - compass.origin.x; compass.y = avatar.y + avatar.height / 2f - compass.origin.y; @@ -210,11 +209,11 @@ public class StatusPane extends Component { busy.x = x + bg.width + 1; busy.y = y + bg.height - 9; } else { - exp.x = x; - exp.y = y; + exp.x = x+2; + exp.y = y+29; hp.x = shieldedHP.x = rawShielding.x = x + 30; - hp.y = shieldedHP.y = rawShielding.y = y + 3; + hp.y = shieldedHP.y = rawShielding.y = y + 1; hpText.scale.set(PixelScene.align(0.5f)); hpText.x = hp.x + 1; @@ -222,12 +221,18 @@ public class StatusPane extends Component { hpText.y -= 0.001f; //prefer to be slightly higher PixelScene.align(hpText); + expText.scale.set(PixelScene.align(0.5f)); + expText.x = exp.x + 1; + expText.y = exp.y + (exp.height - (expText.baseLine()+expText.scale.y))/2f; + expText.y -= 0.001f; //prefer to be slightly higher + PixelScene.align(expText); + heroInfoOnBar.setRect(heroInfo.right(), y, 50, 9); - buffs.setRect( x + 31, y + 9, 50, 8 ); + buffs.setRect( x + 31, y + 7, 50, 8 ); busy.x = x + 1; - busy.y = y + 33; + busy.y = y + 37; } counter.point(busy.center()); @@ -291,7 +296,8 @@ public class StatusPane extends Component { expText.x = hp.x + (128 - expText.width())/2f; } else { - exp.scale.x = (width / exp.width) * Dungeon.hero.exp / Dungeon.hero.maxExp(); + exp.scale.x = (17 / exp.width) * Dungeon.hero.exp / Dungeon.hero.maxExp(); + expText.text(Dungeon.hero.exp + "/" + Dungeon.hero.maxExp()); } if (Dungeon.hero.lvl != lastLvl) { @@ -310,7 +316,7 @@ public class StatusPane extends Component { } else { level.text( Integer.toString( lastLvl ) ); level.measure(); - level.x = x + 27.5f - level.width() / 2f; + level.x = x + 25.5f - level.width() / 2f; level.y = y + 28.0f - level.baseLine() / 2f; } PixelScene.align(level); From 291f11bc4e2734c03d0ded2def70a15dc0c38125 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Fri, 5 Sep 2025 13:36:34 -0400 Subject: [PATCH 04/62] v3.2.4: dark bars in UI for insets now block inputs --- .../shatteredpixeldungeon/scenes/GameScene.java | 9 +++++++++ .../shatteredpixeldungeon/scenes/HeroSelectScene.java | 3 +++ 2 files changed, 12 insertions(+) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index a3a182884..dff2db621 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -133,6 +133,7 @@ import com.watabou.noosa.Group; import com.watabou.noosa.Image; import com.watabou.noosa.NoosaScript; import com.watabou.noosa.NoosaScriptNoLighting; +import com.watabou.noosa.PointerArea; import com.watabou.noosa.SkinnedBlock; import com.watabou.noosa.Visual; import com.watabou.noosa.audio.Sample; @@ -384,6 +385,10 @@ public class GameScene extends PixelScene { SkinnedBlock bar = new SkinnedBlock(uiCamera.width, insets.top, TextureCache.createSolid(0xFF1C1E18)); bar.camera = uiCamera; add(bar); + + PointerArea blocker = new PointerArea(0, 0, uiCamera.width, insets.top); + blocker.camera = uiCamera; + add(blocker); } boss = new BossHealthBar(); @@ -436,6 +441,10 @@ public class GameScene extends PixelScene { bar.camera = uiCamera; bar.y = uiCamera.height - insets.bottom; add(bar); + + PointerArea blocker = new PointerArea(0, uiCamera.height - insets.bottom, uiCamera.width, insets.bottom); + blocker.camera = uiCamera; + add(blocker); } layoutTags(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/HeroSelectScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/HeroSelectScene.java index 3fb5427d3..e9cf6bd06 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/HeroSelectScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/HeroSelectScene.java @@ -336,6 +336,9 @@ public class HeroSelectScene extends PixelScene { SkinnedBlock bar = new SkinnedBlock(Camera.main.width, insets.bottom, TextureCache.createSolid(0xAA000000)); bar.y = h + insets.top; add(bar); + + PointerArea blocker = new PointerArea(0, Camera.main.width - insets.bottom, Camera.main.width, insets.bottom); + add(blocker); } title.setPos(insets.left + (w - title.width()) / 2f, insets.top + (h - HeroBtn.HEIGHT - title.height() - 4)); From 687b97c3a9d96f47018b4fddea4327fb85870584 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Fri, 5 Sep 2025 16:31:48 -0400 Subject: [PATCH 05/62] v3.2.4: added support for 'medium' display cutouts like dynamic island --- .../com/watabou/utils/PlatformSupport.java | 4 +- .../android/AndroidPlatformSupport.java | 30 +++++++++++++ .../scenes/GameScene.java | 42 ++++++++++++++----- .../shatteredpixeldungeon/ui/StatusPane.java | 5 ++- 4 files changed, 68 insertions(+), 13 deletions(-) diff --git a/SPD-classes/src/main/java/com/watabou/utils/PlatformSupport.java b/SPD-classes/src/main/java/com/watabou/utils/PlatformSupport.java index 2d016643f..43fbb0ff8 100644 --- a/SPD-classes/src/main/java/com/watabou/utils/PlatformSupport.java +++ b/SPD-classes/src/main/java/com/watabou/utils/PlatformSupport.java @@ -53,9 +53,9 @@ public abstract class PlatformSupport { ); } - //returns a display cutout (if one is present) in device pixels, or null is none is present + //returns a display cutout (if one is present) in device pixels, or empty if none is present public RectF getDisplayCutout(){ - return null; + return new RectF(); } public abstract void updateSystemUI(); diff --git a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java index 29942aac6..67c9e6964 100644 --- a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java +++ b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java @@ -66,6 +66,35 @@ public class AndroidPlatformSupport extends PlatformSupport { } } + @Override + public RectF getDisplayCutout() { + RectF cutoutRect = new RectF(); + + //some extra logic here is because cutouts can apparently be returned inverted + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + DisplayCutout cutout = AndroidLauncher.instance.getApplicationWindow().getDecorView().getRootWindowInsets().getDisplayCutout(); + + Rect largest = null; + if (cutout != null) { + for (Rect r : cutout.getBoundingRects()) { + if (largest == null + || Math.abs(r.height() * r.width()) > Math.abs(largest.height() * largest.width())) { + largest = r; + } + } + } + + if (largest != null){ + cutoutRect.left = Math.min(largest.left, largest.right); + cutoutRect.right = Math.max(largest.left, largest.right); + cutoutRect.top = Math.min(largest.top, largest.bottom); + cutoutRect.bottom = Math.max(largest.top, largest.bottom); + } + } + + return cutoutRect; + } + @Override public RectF getSafeInsets( int level ) { RectF insets = new RectF(); @@ -90,6 +119,7 @@ public class AndroidPlatformSupport extends PlatformSupport { boolean largeCutout = false; int screenSize = Game.width * Game.height; for (Rect r : cutout.getBoundingRects()){ + //use abs as some cutouts can apparently be returned inverted int cutoutSize = Math.abs(r.height() * r.width()); //display cutouts are considered large if they take up more than 0.605% of the screen //in reality we want less than about 0.5%, but some cutouts over-report their size diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index dff2db621..b88cc431e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -140,6 +140,7 @@ import com.watabou.noosa.audio.Sample; import com.watabou.noosa.particles.Emitter; import com.watabou.noosa.tweeners.Tweener; import com.watabou.utils.Callback; +import com.watabou.utils.DeviceCompat; import com.watabou.utils.GameMath; import com.watabou.utils.PlatformSupport; import com.watabou.utils.Point; @@ -234,7 +235,8 @@ public class GameScene extends PixelScene { } RectF insets = getCommonInsets(); - insets.top = Game.platform.getSafeInsets(PlatformSupport.INSET_LRG).scale(1f/defaultZoom).top; + //we want to check if large is the same as blocking here + float largeInsetTop = Game.platform.getSafeInsets(PlatformSupport.INSET_LRG).scale(1f/defaultZoom).top; scene = this; @@ -368,32 +370,52 @@ public class GameScene extends PixelScene { menu = new MenuPane(); menu.camera = uiCamera; - menu.setPos( uiCamera.width-MenuPane.WIDTH-insets.right, insets.top); + menu.setPos( uiCamera.width-MenuPane.WIDTH-insets.right, largeInsetTop); add(menu); - //TODO buff indicator and boss HP need to be moved down slightly on iOS devices with dynamic island - //TODO buff indicator probably cut off on some Android devices, get display cutout size and check? - //TODO need to reject inputs on the bars (just turn then into hotareas? //TODO make top bar transparent and add 1px of top status and menu bar to it? + //most cutouts supported by the game are small + // but some are more 'medium' can can be supported with a little UI offsetting + float mediumCutoutOffset = 0; + if (largeInsetTop != insets.top){ + //most notably iOS's Dynamic island, which must exist in this case + if (DeviceCompat.isiOS()){ + //TODO we should handle this logic in platformSupport, not hardcode it here + mediumCutoutOffset = 7; + } else if (DeviceCompat.isAndroid()) { + //some android hole punches can also be big too + RectF cutout = Game.platform.getDisplayCutout().scale(1f / defaultZoom); + //if the cutout is positioned to obstruct the buff bar + //TODO could buff bar just be squished in some cases here? + if (cutout.left < 80 + && cutout.top < 10 + && cutout.right > 32 + && cutout.bottom > 11) { + mediumCutoutOffset = (int) Math.floor(cutout.bottom - 11); + } + } + } + status = new StatusPane( SPDSettings.interfaceSize() > 0 ); status.camera = uiCamera; - status.setRect(insets.left, uiSize > 0 ? uiCamera.height-39-insets.bottom : insets.top, uiCamera.width - insets.left - insets.right, 0 ); + StatusPane.cutoutOffset = mediumCutoutOffset; + status.setRect(insets.left, uiSize > 0 ? uiCamera.height-39-insets.bottom : largeInsetTop, uiCamera.width - insets.left - insets.right, 0 ); add(status); - if (uiSize < 2 && insets.top > 0) { - SkinnedBlock bar = new SkinnedBlock(uiCamera.width, insets.top, TextureCache.createSolid(0xFF1C1E18)); + if (uiSize < 2 && largeInsetTop != 0) { + SkinnedBlock bar = new SkinnedBlock(uiCamera.width, largeInsetTop, TextureCache.createSolid(0xFF1C1E18)); bar.camera = uiCamera; add(bar); - PointerArea blocker = new PointerArea(0, 0, uiCamera.width, insets.top); + PointerArea blocker = new PointerArea(0, 0, uiCamera.width, largeInsetTop); blocker.camera = uiCamera; add(blocker); } boss = new BossHealthBar(); boss.camera = uiCamera; - boss.setPos( insets.left + 6 + (uiCamera.width - insets.left - insets.right - boss.width())/2, insets.top + 21); + boss.setPos( insets.left + 6 + (uiCamera.width - insets.left - insets.right - boss.width())/2, largeInsetTop + 21 + mediumCutoutOffset); add(boss); resume = new ResumeIndicator(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java index ef151ec3f..e7aebe87a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java @@ -78,6 +78,9 @@ public class StatusPane extends Component { private boolean large; + //lower the buff indicator to avoid larger cutouts (e.g. iPhone dynamic island) + public static float cutoutOffset; + public StatusPane( boolean large ){ super(); @@ -229,7 +232,7 @@ public class StatusPane extends Component { heroInfoOnBar.setRect(heroInfo.right(), y, 50, 9); - buffs.setRect( x + 31, y + 7, 50, 8 ); + buffs.setRect( x + 31, y + 7 + cutoutOffset, 50, 8 ); busy.x = x + 1; busy.y = y + 37; From 7d81c228a34383285c31c24f5aa3448b8ccc4d8f Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sat, 6 Sep 2025 23:27:40 -0400 Subject: [PATCH 06/62] v3.2.4: slight adjustments to new status pane and menu pane UI --- core/src/main/assets/interfaces/menu_pane.png | Bin 233 -> 242 bytes .../main/assets/interfaces/status_pane.png | Bin 1051 -> 1061 bytes .../scenes/GameScene.java | 21 +++++++++------ .../shatteredpixeldungeon/ui/MenuPane.java | 18 ++++++------- .../shatteredpixeldungeon/ui/StatusPane.java | 24 +++++++++--------- 5 files changed, 34 insertions(+), 29 deletions(-) diff --git a/core/src/main/assets/interfaces/menu_pane.png b/core/src/main/assets/interfaces/menu_pane.png index 83666e69360ad57e106d92858e8bc64ac3936a00..cc6d1d92f5e632e8d9f37fd608f41d86d61ac9e8 100644 GIT binary patch delta 206 zcmaFK_=$0XPJMMlaYjyJXk@(X5gcy=QV$f@*naSW+oOimDSVRYj0Ii_)7X5&>IUP%_?4YSG>8p|de@KG_4 z)kxUN1r#z^)uzPUqI;?!nn&V*f`k{ZBICQo0`YGf1KejzO7sLWGFvgU?qV>K7m;H- zQ4_F2eF4{ua+3v|XXZ3$C2Y-N1WLSOT=7jxTGC(w3q!KEOF+teMO&aN7(8A5T-G@y GGywowkwP#4 delta 197 zcmV;$06PEj0qFsdEPrThVO3dBqo$Q5Cm|#zASx^+DJvu*Bp!Q!b8~oXkCTLhhneSBZG->TZACgA_is!1~4#!QbS09`!K{;dmz*%20jM#AS4}t0!RUw4~hl{ zQ~}kr1T=y20#pHwjs|2tC>jh;R-Mup6r_g00000NkvXXu0mjfc~d?q diff --git a/core/src/main/assets/interfaces/status_pane.png b/core/src/main/assets/interfaces/status_pane.png index 17355fe16caa6510caea275b9e563864366d9d29..cbe1ff0000f7fed1175d9f999b01f5f6cf014921 100644 GIT binary patch delta 778 zcmV+l1NHoy2&D*+EC~Pr06suDRasDxHUEDNV^0_W0007XQchF<0OhwZN&o-?$4Nv% zRCodG+6ikDK@`C8|C^aj4~P<|^b4fe0xA^bKD_lSdn-2-DCttD_zkQG8eH3uowYy~ z*k%eo*qH^KAJ@Wg{F|^Zg?U2n1P#FmH)#a)JQ@x`2otFtT1|~IfI(FAA<93$@~8vcuL&VPZ!K}CTvi@^fOR%}WZ9`|U4RGl0i$rh$Z{?*Uw}5i zI1@fH2%d=A02>al20Q}?kR-quLQD?G0XZNCwFua9H$8oI+})Qc>pk*ruYh=pko122tbkME7+oItHL@1;B1P3 z?TR&KZwatx5(MmiC-4@GNX30)jkQOtRF=p@SZAQ+iA@IP7??al>oa|l$0&b&qF3?+ zosaZOo}%)Bp2;(`-qR;}j?z1NB`?rNCeT?^8Fqso}yQtH+pc!2?3BrcZkocMwS-gcL%WL1cEF2_IRK45D_} ztl2Z98AQj2gdL?AM0pS)f7_u$D*$02h=O%(_-m_=rTtL#Lpm+zBlMUG(+;oMQ z1vX5IQ}(|LeDmY95DpI;G6d!o62~;+HADj8aKuSk~D53(gT0) zh?zAtg-FqCHzGM8+|7ykdsY)j^0*P{0X}$Qg6Fi_lHx(UCSc-;nRsqR5|J!`3yzrJ z5W-jh=N&QLffzY}K?0m3#^rzl1+T zUCagaz=1a`$_s$iVu-JRfL; z3A|Hrz=tdLDu*$h{l!a!H9s<4lImCbq)$oo3%$~3r1_bC>2s3&M9=gEseXT?Px_KX zKhP_EMVjyFm%b*+cl1o(aNt`86~wr50DfeFk>!9KkOOi+4#)vHK)l3bPDmW%x58RL zIN~G>qzxD_kThU0kTzg2kThU0kTzg2kTzg|@%ICHz>ouSz*`>hrlRFX3AlF_|4kAC zM8VFpV2l8!=j{B^)Z+vc?!SLK+~R4Z0YfPFces`T!5s+*jr|>Nbie?#@7?|mH#T4Z z+V^gMhuaPqBEsU@{tmYtFhs53w@=u)!ivsrryO(tezk2MB}}N;^8Z)`;FuA&QO%6@ zQJ4rYUlaFURnOP7kCwlJk2%zyKD*DX4!b2T;VE$n~VHwDPM?sCM yCDse`g871FAOr3N)vKmhAIuZx8GFiF+ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index b88cc431e..fb5c310c2 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -368,11 +368,6 @@ public class GameScene extends PixelScene { int uiSize = SPDSettings.interfaceSize(); - menu = new MenuPane(); - menu.camera = uiCamera; - menu.setPos( uiCamera.width-MenuPane.WIDTH-insets.right, largeInsetTop); - add(menu); - //TODO make top bar transparent and add 1px of top status and menu bar to it? //most cutouts supported by the game are small @@ -397,14 +392,24 @@ public class GameScene extends PixelScene { } } + float screentop = largeInsetTop; + if (screentop == 0 && uiSize == 0){ + screentop--; //on mobile UI, if we render in fullscreen, clip the top 1px; + } + + menu = new MenuPane(); + menu.camera = uiCamera; + menu.setPos( uiCamera.width-MenuPane.WIDTH-insets.right, screentop); + add(menu); + status = new StatusPane( SPDSettings.interfaceSize() > 0 ); status.camera = uiCamera; StatusPane.cutoutOffset = mediumCutoutOffset; - status.setRect(insets.left, uiSize > 0 ? uiCamera.height-39-insets.bottom : largeInsetTop, uiCamera.width - insets.left - insets.right, 0 ); + status.setRect(insets.left, uiSize > 0 ? uiCamera.height-39-insets.bottom : screentop, uiCamera.width - insets.left - insets.right, 0 ); add(status); if (uiSize < 2 && largeInsetTop != 0) { - SkinnedBlock bar = new SkinnedBlock(uiCamera.width, largeInsetTop, TextureCache.createSolid(0xFF1C1E18)); + SkinnedBlock bar = new SkinnedBlock(uiCamera.width, largeInsetTop, TextureCache.createSolid(0x88000000)); bar.camera = uiCamera; add(bar); @@ -415,7 +420,7 @@ public class GameScene extends PixelScene { boss = new BossHealthBar(); boss.camera = uiCamera; - boss.setPos( insets.left + 6 + (uiCamera.width - insets.left - insets.right - boss.width())/2, largeInsetTop + 21 + mediumCutoutOffset); + boss.setPos( (uiCamera.width - boss.width())/2, screentop + 26); add(boss); resume = new ResumeIndicator(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java index 829f36118..01c3b87d4 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java @@ -75,10 +75,10 @@ public class MenuPane extends Component { protected void createChildren() { super.createChildren(); - bg = new Image(Assets.Interfaces.MENU, 1, 0, 31, 20); + bg = new Image(Assets.Interfaces.MENU, 1, 0, 31, 21); add(bg); - versionOverflowBG = new NinePatch(bg.texture, 1, 23, 6, 7, 3, 0, 2, 0); + versionOverflowBG = new NinePatch(bg.texture, 1, 22, 6, 8, 3, 0, 2, 0); add(versionOverflowBG); version = new BitmapText( "v" + Game.version , PixelScene.pixelFont); @@ -168,14 +168,14 @@ public class MenuPane extends Component { float overFlow = version.width()-(bg.width()-4-rightMargin); if (overFlow >= 1){ version.x = x + 2 - overFlow; - versionOverflowBG.size(overFlow+3, 7); + versionOverflowBG.size(overFlow+3, 8); versionOverflowBG.x = version.x-3; versionOverflowBG.y = y; } else { version.x = x + 3; versionOverflowBG.visible = false; } - version.y = y + 2 - (version.baseLine()*version.scale.y)/2f; + version.y = y + 3 - (version.baseLine()*version.scale.y)/2f; version.y -= .001f; PixelScene.align(version); @@ -184,7 +184,7 @@ public class MenuPane extends Component { btnJournal.setPos( btnMenu.left() - btnJournal.width() + 2, y ); depthIcon.x = btnJournal.left() - 7 + (7 - depthIcon.width())/2f - 0.1f; - depthIcon.y = y+7; + depthIcon.y = y+8; PixelScene.align(depthIcon); depthText.scale.set(PixelScene.align(0.67f)); @@ -239,7 +239,7 @@ public class MenuPane extends Component { super(); width = bg.width + 4; - height = bg.height + 9; + height = bg.height + 10; } @Override @@ -267,7 +267,7 @@ public class MenuPane extends Component { super.layout(); bg.x = x + 2; - bg.y = y + 7; + bg.y = y + 8; journalIcon.x = bg.x + (bg.width() - journalIcon.width())/2f; journalIcon.y = bg.y + (bg.height() - journalIcon.height())/2f; @@ -372,7 +372,7 @@ public class MenuPane extends Component { super(); width = image.width + 4; - height = image.height + 9; + height = image.height + 10; } @Override @@ -388,7 +388,7 @@ public class MenuPane extends Component { super.layout(); image.x = x + 2; - image.y = y + 7; + image.y = y + 8; } @Override diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java index e7aebe87a..5993b7efb 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java @@ -90,7 +90,7 @@ public class StatusPane extends Component { if (large) bg = new NinePatch( asset, 0, 64, 41, 39, 33, 0, 4, 0 ); //right part is transparent now so Ninepatching doesn't actually do anything - else bg = new NinePatch( asset, 0, 0, 128, 35, 85, 0, 45, 0 ); + else bg = new NinePatch( asset, 0, 0, 128, 38, 85, 0, 45, 0 ); add( bg ); heroInfo = new Button(){ @@ -121,16 +121,16 @@ public class StatusPane extends Component { add( compass ); if (large) rawShielding = new Image(asset, 0, 112, 128, 9); - else rawShielding = new Image(asset, 0, 40, 50, 4); + else rawShielding = new Image(asset, 0, 44, 50, 4); rawShielding.alpha(0.5f); add(rawShielding); if (large) shieldedHP = new Image(asset, 0, 112, 128, 9); - else shieldedHP = new Image(asset, 0, 40, 50, 4); + else shieldedHP = new Image(asset, 0, 44, 50, 4); add(shieldedHP); if (large) hp = new Image(asset, 0, 103, 128, 9); - else hp = new Image(asset, 0, 36, 50, 4); + else hp = new Image(asset, 0, 40, 50, 4); add( hp ); hpText = new BitmapText(PixelScene.pixelFont); @@ -147,7 +147,7 @@ public class StatusPane extends Component { add(heroInfoOnBar); if (large) exp = new Image(asset, 0, 121, 128, 7); - else exp = new Image(asset, 0, 44, 17, 4); + else exp = new Image(asset, 0, 48, 17, 4); add( exp ); expText = new BitmapText(PixelScene.pixelFont); @@ -173,7 +173,7 @@ public class StatusPane extends Component { @Override protected void layout() { - height = large ? 39 : 35; + height = large ? 39 : 38; bg.x = x; bg.y = y; @@ -181,10 +181,10 @@ public class StatusPane extends Component { else bg.size( width, bg.height ); avatar.x = bg.x - avatar.width / 2f + 15; - avatar.y = bg.y - avatar.height / 2f + (large ? 15 : 14); + avatar.y = bg.y - avatar.height / 2f + 16; PixelScene.align(avatar); - heroInfo.setRect( x, y, 30, large ? 40 : 35 ); + heroInfo.setRect( x, y, 30, large ? 40 : 36 ); compass.x = avatar.x + avatar.width / 2f - compass.origin.x; compass.y = avatar.y + avatar.height / 2f - compass.origin.y; @@ -213,10 +213,10 @@ public class StatusPane extends Component { busy.y = y + bg.height - 9; } else { exp.x = x+2; - exp.y = y+29; + exp.y = y+30; hp.x = shieldedHP.x = rawShielding.x = x + 30; - hp.y = shieldedHP.y = rawShielding.y = y + 1; + hp.y = shieldedHP.y = rawShielding.y = y + 2; hpText.scale.set(PixelScene.align(0.5f)); hpText.x = hp.x + 1; @@ -232,7 +232,7 @@ public class StatusPane extends Component { heroInfoOnBar.setRect(heroInfo.right(), y, 50, 9); - buffs.setRect( x + 31, y + 7 + cutoutOffset, 50, 8 ); + buffs.setRect( x + 31, y + 8 + cutoutOffset, 50, 8 ); busy.x = x + 1; busy.y = y + 37; @@ -320,7 +320,7 @@ public class StatusPane extends Component { level.text( Integer.toString( lastLvl ) ); level.measure(); level.x = x + 25.5f - level.width() / 2f; - level.y = y + 28.0f - level.baseLine() / 2f; + level.y = y + 31.0f - level.baseLine() / 2f; } PixelScene.align(level); } From b142589b0455f62700083de5e7c7a264e0df5fb6 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 7 Sep 2025 15:18:51 -0400 Subject: [PATCH 07/62] v3.2.4: adjusted how buff bar handles display cutouts --- .../scenes/GameScene.java | 19 +++---- .../ui/BuffIndicator.java | 54 +++++++++++++++---- .../shatteredpixeldungeon/ui/StatusPane.java | 4 +- 3 files changed, 55 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index fb5c310c2..e1e9865ab 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -368,26 +368,23 @@ public class GameScene extends PixelScene { int uiSize = SPDSettings.interfaceSize(); - //TODO make top bar transparent and add 1px of top status and menu bar to it? - - //most cutouts supported by the game are small - // but some are more 'medium' can can be supported with a little UI offsetting - float mediumCutoutOffset = 0; + //Some more medium sized display cutouts can obstruct the buff bar, so we limit the length + // of the 1st row in some cases + float buffBarTopRowMaxWidth = 50; //default max width if (largeInsetTop != insets.top){ //most notably iOS's Dynamic island, which must exist in this case if (DeviceCompat.isiOS()){ - //TODO we should handle this logic in platformSupport, not hardcode it here - mediumCutoutOffset = 7; + //TODO bad to hardcode this atm, need to change this so platformsupport returns cutout dimensions + buffBarTopRowMaxWidth = 15; } else if (DeviceCompat.isAndroid()) { //some android hole punches can also be big too RectF cutout = Game.platform.getDisplayCutout().scale(1f / defaultZoom); //if the cutout is positioned to obstruct the buff bar - //TODO could buff bar just be squished in some cases here? if (cutout.left < 80 && cutout.top < 10 && cutout.right > 32 - && cutout.bottom > 11) { - mediumCutoutOffset = (int) Math.floor(cutout.bottom - 11); + && cutout.bottom > 12) { + buffBarTopRowMaxWidth = cutout.left - 32; //subtract starting position } } } @@ -404,7 +401,7 @@ public class GameScene extends PixelScene { status = new StatusPane( SPDSettings.interfaceSize() > 0 ); status.camera = uiCamera; - StatusPane.cutoutOffset = mediumCutoutOffset; + StatusPane.buffBarTopRowMaxWidth = buffBarTopRowMaxWidth; status.setRect(insets.left, uiSize > 0 ? uiCamera.height-39-insets.bottom : screentop, uiCamera.width - insets.left - insets.right, 0 ); add(status); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java index 23c665784..6f44e9de0 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java @@ -148,6 +148,8 @@ public class BuffIndicator extends Component { private Char ch; private boolean large = false; + + public float firstRowWidth = -1; public BuffIndicator( Char ch, boolean large ) { super(); @@ -225,32 +227,63 @@ public class BuffIndicator extends Component { buffButtons.put( buff, icon ); } } + + //TODO several aspects of the layout code have been a bit hackily changed to support 2 rows + // should clean this up //layout + int row = 0; int pos = 0; float lastIconLeft = 0; + int total = 0; for (BuffButton icon : buffButtons.values()){ + if (total >= 14){ //buff bar supports a max of 14 buffs at once + icon.visible = false; + continue; + } + icon.visible = true; + + icon.topOffset = (row > 0 && !large) ? -1 : 0; icon.updateIcon(); //button areas are slightly oversized, especially on small buttons - icon.setRect(x + pos * (size + 1), y, size + 1, size + (large ? 0 : 5)); + icon.setRect(x + pos * (size + 1), y + row*(size+1)-icon.topOffset, size + 1, size + (large ? 0 : 5)); PixelScene.align(icon); pos++; - icon.visible = icon.left() <= right(); lastIconLeft = icon.left(); + + if ((row+1)*(size+1) <= height + && (pos * (size + 1) > width || (row == 0 && firstRowWidth != -1 && pos * (size + 1) > firstRowWidth))){ + row++; + pos = 0; + } + total++; } buffsHidden = false; //squish buff icons together if there isn't enough room float excessWidth = lastIconLeft - right(); - if (excessWidth > 0) { - float leftAdjust = excessWidth/(buffButtons.size()-1); - //can't squish by more than 50% on large and 62% on small - if (large && leftAdjust >= size*0.48f) leftAdjust = size*0.5f; - if (!large && leftAdjust >= size*0.62f) leftAdjust = size*0.65f; - float cumulativeAdjust = leftAdjust * (buffButtons.size()-1); - ArrayList buttons = new ArrayList<>(buffButtons.values()); + if (excessWidth > 0) { + //if multiple rows, only compress last row + ArrayList buttons = new ArrayList<>(); + float lastRowY = y + row*(size+1); + int i = 1; + for (BuffButton button : buffButtons.values()){ + if (i > 14){ + button.visible = false; + buffsHidden = true; + continue; + } + if (button.top()+button.topOffset == lastRowY){ + buttons.add(button); + } + i++; + } + + float leftAdjust = excessWidth/(buttons.size()-1); + float cumulativeAdjust = leftAdjust * (buttons.size()-1); + Collections.reverse(buttons); for (BuffButton icon : buttons) { icon.setPos(icon.left() - cumulativeAdjust, icon.top()); @@ -277,6 +310,7 @@ public class BuffIndicator extends Component { private Buff buff; private boolean large; + private int topOffset = 0; public Image grey; //only for small public BitmapText text; //only for large @@ -329,7 +363,7 @@ public class BuffIndicator extends Component { protected void layout() { super.layout(); grey.x = icon.x = this.x + (large ? 0 : 1); - grey.y = icon.y = this.y + (large ? 0 : 2); + grey.y = icon.y = this.y + (large ? 0 : 2) + topOffset; if (text.width > width()){ text.scale.set(PixelScene.align(0.5f)); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java index 5993b7efb..05778f7dd 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java @@ -80,6 +80,7 @@ public class StatusPane extends Component { //lower the buff indicator to avoid larger cutouts (e.g. iPhone dynamic island) public static float cutoutOffset; + public static float buffBarTopRowMaxWidth = 50; public StatusPane( boolean large ){ super(); @@ -232,7 +233,8 @@ public class StatusPane extends Component { heroInfoOnBar.setRect(heroInfo.right(), y, 50, 9); - buffs.setRect( x + 31, y + 8 + cutoutOffset, 50, 8 ); + buffs.firstRowWidth = buffBarTopRowMaxWidth; + buffs.setRect( x + 31, y + 8 + cutoutOffset, 50, 15 ); busy.x = x + 1; busy.y = y + 37; From 88a59ff342436582d67322510870f4bb15a38cf2 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 7 Sep 2025 16:44:56 -0400 Subject: [PATCH 08/62] v3.2.4: adjusted iOS safe inset sizes --- .../ios/IOSPlatformSupport.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java b/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java index 0dfbbb885..4debb6072 100644 --- a/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java +++ b/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java @@ -62,25 +62,22 @@ public class IOSPlatformSupport extends PlatformSupport { public RectF getSafeInsets(int level) { RectF insets = super.getSafeInsets(INSET_ALL); + //magic number BS for larger status bar caused by dynamic island + boolean hasDynamicIsland = insets.top / Gdx.graphics.getBackBufferScale() >= 51; + //iOS gives us ALL insets by default, and so we need to filter from there: //ignore the home indicator if we're in fullscreen if (!supportsFullScreen() || SPDSettings.fullscreen()){ insets.bottom = 0; - } else { - //otherwise bottom inset is pretty big, halve it - insets.bottom /= 2; } //only cutouts can be on top/left/right, which are never blocking if (level == INSET_BLK){ insets.left = insets.top = insets.right = 0; - } else if (level == INSET_LRG){ - //Dynamic Island counts as a 'small cutout', we have to use status bar height to get it =I - double statusBarHeight = insets.top / Gdx.graphics.getBackBufferScale(); - if (statusBarHeight >= 51){ //magic number BS for larger status bar caused by island - insets.left = insets.top = insets.right = 0; - } + } else if (level == INSET_LRG && hasDynamicIsland){ + //Dynamic Island counts as a 'small cutout' + insets.left = insets.top = insets.right = 0; } //if we are in landscape, the display cutout is only actually on one side, so cancel the other @@ -92,6 +89,12 @@ public class IOSPlatformSupport extends PlatformSupport { } } + //finally iOS is very conservative with these insets, we can shrink them a bit. + insets.top /= hasDynamicIsland ? 1.2f : 1.4f; + insets.left /= hasDynamicIsland ? 1.2f : 1.4f; + insets.right /= hasDynamicIsland ? 1.2f : 1.4f; + insets.bottom /= 2; //home bar inset is especially big for no reason + return insets; } From 0e9477f4a0f33bec3f7b272a839c10330e17bec3 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Tue, 9 Sep 2025 13:25:02 -0400 Subject: [PATCH 09/62] v3.2.4: implemented a new title background! --- core/src/main/assets/splashes/title/archs.png | Bin 0 -> 74297 bytes .../assets/splashes/title/back_clusters.png | Bin 0 -> 6025 bytes .../assets/splashes/title/front_small.png | Bin 0 -> 24401 bytes .../main/assets/splashes/title/mid_mixed.png | Bin 0 -> 213587 bytes .../shatteredpixeldungeon/Assets.java | 7 + .../scenes/AboutScene.java | 7 +- .../scenes/ChangesScene.java | 9 +- .../scenes/InterlevelScene.java | 2 + .../scenes/JournalScene.java | 9 +- .../scenes/NewsScene.java | 7 +- .../scenes/PixelScene.java | 2 + .../scenes/RankingsScene.java | 9 +- .../scenes/StartScene.java | 9 +- .../scenes/SupporterScene.java | 7 +- .../scenes/SurfaceScene.java | 10 +- .../scenes/TitleScene.java | 7 +- .../scenes/WelcomeScene.java | 7 +- .../ui/TitleBackground.java | 570 ++++++++++++++++++ 18 files changed, 615 insertions(+), 47 deletions(-) create mode 100644 core/src/main/assets/splashes/title/archs.png create mode 100644 core/src/main/assets/splashes/title/back_clusters.png create mode 100644 core/src/main/assets/splashes/title/front_small.png create mode 100644 core/src/main/assets/splashes/title/mid_mixed.png create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java diff --git a/core/src/main/assets/splashes/title/archs.png b/core/src/main/assets/splashes/title/archs.png new file mode 100644 index 0000000000000000000000000000000000000000..cefda217e61192a7ff420542561fd372e1eae6d5 GIT binary patch literal 74297 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%0DDou*P&d`_ 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%0Absn`^Ki4_Z2Udm`C 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 z00000000000000000000000000000000000000000000000000000000DrKbOIr&E TLwRYu00000NkvXXu0mjf$X`v! literal 0 HcmV?d00001 diff --git a/core/src/main/assets/splashes/title/back_clusters.png b/core/src/main/assets/splashes/title/back_clusters.png new file mode 100644 index 0000000000000000000000000000000000000000..73e1f74923f2cd8456dc45f06ef95ecbcdba3b14 GIT binary patch literal 6025 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

?AT-NVrJcV_%q?$c zvNJDDlcblf{2+873~N$A1aGKR3}qb)|A!<)h-c1PC)VAa1>#}h^ufQrv#V>FXW`wU z#v?oR9Bz9k$5TkCarBcc)wTG~HQ^{!Mt4N+>?0-59YSozOIGyubmdX3H$Ho_6wLsa zvHB;*o3|k|vanFfKiKElF(%Mb`1{RXqJ(MDdalR=>SYp&en5%@HTFrQ4XKq2Yp8DJ zeMYPM;O4yGc_HScc(Qn%ud93DM5i_*p99EBn|?|d^y2Yr6_v}RyjPPzTnK@LMTgRm z(3Xdxf`Y}8z(ouzZ%yB!7t()g<_l1E82oWk{!iM&5D^JoHHZLnHXv>NuzZ%;lCPhP z_Z9TSSQX>>kYf_Za#!8)>{EmtZbb`0&OaXd+ZZ7tqDYze0P31~+&@iiGwZ@hqhAu!{4Yud9IV0j>uZ

|A3YFJGfA4Me|tmet+Z=rHjGP#;=cQXN0&6& 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 M>IQ1H4;*6t4*{S1r~m)} literal 0 HcmV?d00001 diff --git a/core/src/main/assets/splashes/title/mid_mixed.png b/core/src/main/assets/splashes/title/mid_mixed.png new file mode 100644 index 0000000000000000000000000000000000000000..30c31b9dc1e7c1cf562724df5980890f9b5cdc2a GIT binary patch literal 213587 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%0Ah8sw9T8ve{Xq zP{Dq*hBJc@)|{pt?i&2|yhq8+-C=mB@wok3eX4-wH5!HOUhlULs~4nT6V(hFTJ!!_i=P zE0h@kANs#nH|>n%{PfA#hf@7HF~^u@58O!#bw52QeU-0u&3Lx2-{8QAhjAf?Sz-Kv z&8&23@zX=kXIwlXw>%&34XUkF`;-6R>EehN_C?()Nw^Wq`pZOREMH;k^Jzc+Soump zcpben_?^<_{5MIr2IJu}$BTFn0Q2NE+F%;6S0EC+J!_}Xct@;r z-aM~a{xXOv?x}4}$}R*Rm*~#~Ko60T!!!<+oq?)($<2a{q#70z@2i1&&`c@0j(Ssz z{B|4waM35%r>m&V?UH3o!~42=8oBTfo=|fewGDBwr)sBILNsl4A|9JqcAz(gr_JrA zeGbyd?Hv53x1UV@Iq*0_v^OPHoo<$m6gCh+xY$)j7O!PU0a)t}uO{1f)L(n~%&Wne zs=)7~A+=$1VPyKQoL0*Ed$=$6lN<;#Qyd`fz*g7ed!z`?Eg(}mI{s8;5jf`wJ`kl` za~g`lNaJl*6eqgnyCXAIp&Ri%4#pQu0d2E?RBL=Z8@cWgg&ljmoa|@g9(2NmzxzOT z%m|pQC#sw)v~;W%=jVO4+x9PC{reP4z<)|`4u#jme2%cS;B7YgavGyPf%-0}xiI9>*h&qb7J=W#Q+7_^ zL@NgOtx0Z8;1>VqbVrLhs&=YfZ~Zx42FrbaV^@{VHwx7(ql?cA0D!GM?Ghn2Ggc+EWc&S2arM%*O)j^gNyuqvz+XpCi}bs24r(lu9B07c>r&B_gIgoXt`E>d z!yrNkVW-ybX54kO>UMoD5d9INpb}^b(Js-Se}Cx5P^zXdeN|^z;LZ@n%#GgO|3dI$ zvOqMYA)(5B-qIf2+2!b2{`Dh#$zOFlygCjZj~98n#e zGQ6Sgb)hJ$zx3!T@M7(j3PXZNTIy}B2mCP$O8X2foqCjxAK;kWE^T8u!T7tRKJ3*{2#&%)g$h%35uy(IPd+!#K9skxyv!N-HTDo3B|;x*D{`eX8RnOaG^_x$HEt_DwZL^4S4pqqBR_Y)fGC* zky}X+V?v;Owt3UK+4G5UA>7H)$ZPmW!2}OTMz5XD#OMWzMPG)^mR-?H%|HQSd~e!R zIRja6Vc8Uwu^Pb#>XY`aGS>;=Uyb3NWNlkY0Mim_(jtHWEuC}1 + */ + +package com.shatteredpixel.shatteredpixeldungeon.ui; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.watabou.gltextures.TextureCache; +import com.watabou.noosa.Game; +import com.watabou.noosa.Group; +import com.watabou.noosa.Image; +import com.watabou.noosa.TextureFilm; +import com.watabou.noosa.ui.Component; +import com.watabou.utils.Random; +import com.watabou.utils.RectF; + +import java.util.ArrayList; + +public class TitleBackground extends Component { + + public static float SCROLL_SPEED = 15f; + + private float density = 1f; + + //Arch back layer + private static final TextureFilm ARCH_FILM = new TextureFilm(Assets.Splashes.Title.ARCHS, 333, 100); + private static Group archLayer; + private static ArrayList archs; + + //Cluster far layer + private static TextureFilm CLUSTER_FILM = new TextureFilm(Assets.Splashes.Title.BACK_CLUSTERS, 450, 250); + private static ArrayList clusters; + private static Group clusterLayer; + + //Mixed Item middle layer 1 + private static TextureFilm MID_FILM = new TextureFilm(Assets.Splashes.Title.MID_MIXED, 273, 242); + private static ArrayList mids1; + private static Group mids1Layer; + //Mixed Item middle layer 2 + private static ArrayList mids2; + private static Group mids2Layer; + + //Small Item front layer + private static TextureFilm SMALL_FILM = new TextureFilm(Assets.Splashes.Title.FRONT_SMALL, 112, 116); + private static ArrayList smalls; + private static Group smallLayer; + + private static boolean wasLandscape; + private static float oldBaseScale = 1; + private static float oldWidth = 0; + + public static void reset(){ + archs = null; + clusters = null; + mids1 = null; + mids2 = null; + smalls = null; + } + + public TitleBackground(int width, int height){ + super(); + x = y = 0; + this.width = width; + this.height = height; + setupObjects(); + } + + protected void setupObjects() { + + boolean landscape = width > height; + + float scale = height / 450f; + + //we reset in this case as scale changes + if (archs != null && (landscape != wasLandscape)){ + archs = null; + clusters = null; + mids1 = null; + mids2 = null; + smalls = null; + } + wasLandscape = landscape; + + archLayer = new Group(); + if (archs == null) { + archs = new ArrayList<>(); + } else { + convertArchLayer(archs, archLayer, scale); + } + add(archLayer); + + Image darkness = new Image(TextureCache.createGradient(0x00000000, 0x11000000, 0x22000000, 0x33000000, 0x44000000, 0x88000000)); + darkness.angle = 90; + darkness.x = width; + darkness.scale.x = height/6f; + darkness.scale.y = width; + add(darkness); + + if (!landscape){ + scale /= 1.5f; + oldBaseScale /= 1.5f; + } + + density = width / (800f * scale); + density = (density+0.5f)/1.5f; //pull density 33% of the way toward 1 if it is beyond it + + clusterLayer = new Group(); + if (clusters == null) { + clusters = new ArrayList<>(); + } else { + convertFloatingLayer(clusters, clusterLayer, scale, oldWidth); + } + add(clusterLayer); + + mids1Layer = new Group(); + if (mids1 == null){ + mids1 = new ArrayList<>(); + } else { + convertFloatingLayer(mids1, mids1Layer, scale, oldWidth); + } + add(mids1Layer); + + mids2Layer = new Group(); + if (mids2 == null){ + mids2 = new ArrayList<>(); + } else { + convertFloatingLayer(mids2, mids2Layer, scale, oldWidth); + } + add(mids2Layer); + + smallLayer = new Group(); + if (smalls == null){ + smalls = new ArrayList<>(); + } else { + convertFloatingLayer(smalls, smallLayer, scale, oldWidth); + } + add(smallLayer); + + oldWidth = width/scale; + if (!landscape){ + scale *= 1.5f; + } + oldBaseScale = scale; + + } + + //*** Logic for converting images between scene resets. *** + + //creates a new instance of a disposed of image, for recreation of this component after scene transition + protected Image convertImage(Image oldImg, float newBaseScale){ + Image newImg = new Image(oldImg.texture); + newImg.frame(oldImg.frame()); + float oldScale = oldImg.scale.x / oldBaseScale; + newImg.scale.set(newBaseScale*oldScale); + newImg.brightness(oldImg.rm); + float scaleDiff = newImg.scale.y / oldImg.scale.y; + newImg.x = oldImg.x * scaleDiff; + newImg.y = oldImg.y * scaleDiff; + newImg.angle = oldImg.angle; + return newImg; + } + + protected void convertArchLayer(ArrayList layerList, Group layerGroup, float newBaseScale){ + ArrayList oldImages = new ArrayList<>(layerList); + layerList.clear(); + float rightMost = 0; + for (int i = 0; i < oldImages.size(); i++){ + Image oldArch = oldImages.get(i); + Image newArch = convertImage(oldArch, newBaseScale); + layerList.add(newArch); + layerGroup.add(newArch); + rightMost = Math.max(rightMost, newArch.x + newArch.width()); + //if we're at the end of a row and haven't hit the end yet, add more archs! + while (newArch.x+newArch.width() < width + && (i == oldImages.size()-1 || oldImages.get(i+1).y > oldArch.y)){ + Image extraArch = new Image(Assets.Splashes.Title.ARCHS); + extraArch.frame(getArchFrame()); + extraArch.scale.set(newBaseScale); + extraArch.x = newArch.x + newArch.width(); + extraArch.x -= 9 * newArch.scale.x; //still want to inset here + extraArch.y = newArch.y; //y inset already done + layerList.add(extraArch); + layerGroup.add(extraArch); + newArch = extraArch; + } + } + } + + protected void convertFloatingLayer(ArrayList layerList, Group layerGroup, float newBaseScale, float oldWidth){ + ArrayList oldImages = new ArrayList<>(layerList); + layerList.clear(); + + float xShift = (width()/newBaseScale)/oldWidth; + for (int i = 0; i < oldImages.size(); i++){ + Image oldImage = oldImages.get(i); + Image newImage = convertImage(oldImage, newBaseScale); + if (newImage.x > 0) { + newImage.x *= xShift; + } + layerList.add(newImage); + layerGroup.add(newImage); + } + } + + ArrayList toMove = new ArrayList<>(); + + @Override + public synchronized void update() { + super.update(); + + float scale = height / 450f; + float shift = Game.elapsed * SCROLL_SPEED * scale; + + updateArchLayer(scale, shift); + if (width <= height){ + scale /= 1.5f; + } + shift *= 2f; + updateClusterLayer(scale, shift); + shift *= 1.5f; + updateMid1Layer(scale, shift); + shift *= 1.5f; + updateMid2Layer(scale, shift); + shift *= 1.5f; + updateFrontLayer(scale, shift); + + } + + //*** Arch layer logic *** + + private static final float[] INIT_ARCH_CHANCES = {5, 5, 2, 2, 2, 2}; + private static float[] arch_chances = INIT_ARCH_CHANCES.clone(); + + public RectF getArchFrame(){ + + int tile = Random.chances(arch_chances); + if (tile == -1){ + arch_chances = INIT_ARCH_CHANCES.clone(); + tile = Random.chances(arch_chances); + } + arch_chances[tile]--; + + return ARCH_FILM.get(tile); + } + + private void updateArchLayer(float scale, float shift){ + float bottom = 0; + + //pass over existing archs, raise them + for (Image arch : archs){ + arch.y -= shift; + if (arch.y + arch.height() < 0){ + toMove.add(arch); + } else if (arch.y + arch.height() > bottom){ + bottom = arch.y + arch.height(); + } + } + + //move any archs that scrolled off camera to the bottom + if (!toMove.isEmpty()){ + //we know it'll be one row + for (Image arch : toMove){ + arch.frame(getArchFrame()); + arch.y = bottom - 5*scale; + } + bottom += 100*scale; //arch height + toMove.clear(); + } + + //if we aren't low enough, add more arch layers + while (bottom < height){ + float left = archs.isEmpty() ? -Random.IntRange(5, 100) : archs.get(0).x; + while (left < width){ + Image arch = new Image(Assets.Splashes.Title.ARCHS); + arch.frame(getArchFrame()); + arch.scale.set(scale); + arch.x = left; + arch.y = bottom - 5*scale; + archLayer.add(arch); + archs.add(arch); + left += arch.width() - (9 * scale); + } + bottom += 100*scale; //arch height + } + + } + + //*** Cluster layer logic *** + + private static final float[] INIT_CLUSTER_CHANCES = {2, 2}; + private static float[] cluster_chances = INIT_CLUSTER_CHANCES.clone(); + + public RectF getClusterFrame(){ + + int tile = Random.chances(cluster_chances); + if (tile == -1){ + cluster_chances = INIT_CLUSTER_CHANCES.clone(); + tile = Random.chances(cluster_chances); + } + cluster_chances[tile]--; + + return CLUSTER_FILM.get(tile); + } + + private void updateClusterLayer(float scale, float shift){ + float bottom = 0; + float lastX = 0; + + for (Image cluster : clusters){ + cluster.y -= shift; + if (cluster.y + cluster.height() < -20){ + toMove.add(cluster); + } else if (cluster.y + cluster.height() > bottom){ + bottom = cluster.y + cluster.height(); + lastX = cluster.x; + } + } + + if (!toMove.isEmpty()){ + for (Image cluster : toMove){ + cluster.frame(getClusterFrame()); + float flex = 0; + do { + cluster.x = Random.Float(-cluster.width()/3f, width - 2*cluster.width()/3f); + flex += 1; + } while (Math.abs(cluster.x - lastX) < density*(cluster.width()/2f - flex)); + cluster.y = bottom - cluster.height() + Random.Float(cluster.height()/2f, cluster.height())/density; + cluster.angle = Random.Float(-20, 20); + bottom = cluster.y + cluster.height(); + lastX = cluster.x; + } + toMove.clear(); + } + + //clusters are 250 tall, add a bit for safety + float padding = 300 - (300/2f / density); + while (bottom < (height + padding)){ + Image cluster = new Image(Assets.Splashes.Title.BACK_CLUSTERS); + cluster.frame(getClusterFrame()); + cluster.scale.set(scale); + + float flex = 0; + do { + cluster.x = Random.Float(-cluster.width()/3f, width - 2*cluster.width()/3f); + flex += 1; + } while (Math.abs(cluster.x - lastX) < density*(cluster.width()/2f - flex)); + cluster.y = bottom - cluster.height() + Random.Float(cluster.height()/2f, cluster.height())/density; + cluster.angle = Random.Float(-20, 20); + + cluster.brightness(0.75f); + + clusters.add(cluster); + clusterLayer.add(cluster); + + bottom = cluster.y + cluster.height(); + lastX = cluster.x; + } + } + + //*** Mid layer (1 and 2) logic *** + + private static final float[] INIT_MID_CHANCES = {1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; + private static float[] mid_chances = INIT_MID_CHANCES.clone(); + + public RectF getMidFrame(){ + + int tile = Random.chances(mid_chances); + if (tile == -1){ + mid_chances = INIT_MID_CHANCES.clone(); + tile = Random.chances(mid_chances); + } + mid_chances[tile]--; + + return MID_FILM.get(tile); + } + + private void updateMid1Layer(float scale, float shift){ + float bottom = 0; + float lastX = 0; + + for (Image mid : mids1){ + mid.y -= shift; + if (mid.y + mid.height() < -20){ + toMove.add(mid); + } else if (mid.y + mid.height() > bottom){ + bottom = mid.y + mid.height(); + lastX = mid.x; + } + } + + if (!toMove.isEmpty()){ + for (Image mid : toMove){ + mid.frame(getMidFrame()); + float flex = 0; + do { + mid.x = Random.Float(-mid.width()/3f, width - 2*mid.width()/3f); + flex += 1; + } while (Math.abs(mid.x - lastX) < density*(mid.width()*0.75f - flex)); + mid.y = bottom - mid.height() + Random.Float(mid.height()*0.75f, mid.height())/density; + mid.angle = Random.Float(-20, 20); + bottom = mid.y + mid.height(); + lastX = mid.x; + } + toMove.clear(); + } + + //mids are ~250 tall, add a bit for safety + float padding = 300 - (300/2f / density); + while (bottom < (height + padding)){ + Image mid = new Image(Assets.Splashes.Title.MID_MIXED); + mid.frame(getMidFrame()); + mid.scale.set(scale * Random.Float(0.75f, 1.25f)); + + float flex = 0; + do { + mid.x = Random.Float(-mid.width()/3f, width - 2*mid.width()/3f); + flex += 1; + } while (Math.abs(mid.x - lastX) < density*(mid.width()*0.75f - flex)); + mid.y = bottom - mid.height() + Random.Float(mid.height()/2f, mid.height())/density; + mid.angle = Random.Float(-20, 20); + + mids1.add(mid); + mids1Layer.add(mid); + + bottom = mid.y + mid.height(); + lastX = mid.x; + } + } + + private void updateMid2Layer(float scale, float shift){ + float bottom = 0; + float lastX = 0; + + for (Image mid : mids2){ + mid.y -= shift; + if (mid.y + mid.height() < -20){ + toMove.add(mid); + } else if (mid.y + mid.height() > bottom){ + bottom = mid.y + mid.height(); + lastX = mid.x; + } + } + + if (!toMove.isEmpty()){ + for (Image mid : toMove){ + mid.frame(getMidFrame()); + float flex = 0; + do { + mid.x = Random.Float(-mid.width()/3f, width - 2*mid.width()/3f); + flex += 1; + } while (Math.abs(mid.x - lastX) < density*(mid.width()*0.75f - flex)); + mid.y = bottom - mid.height() + Random.Float(mid.height()/2f, mid.height())/density; + mid.angle = Random.Float(-20, 20); + bottom = mid.y + mid.height(); + lastX = mid.x; + } + toMove.clear(); + } + + //mids are ~250 tall, add a bit for safety + float padding = 300 - (300/2f / density); + while (bottom < (height + padding)){ + Image mid = new Image(Assets.Splashes.Title.MID_MIXED); + mid.frame(getMidFrame()); + mid.scale.set(scale * Random.Float(1.25f, 1.75f)); + + float flex = 0; + do { + mid.x = Random.Float(-mid.width()/3f, width - 2*mid.width()/3f); + flex += 1; + } while (Math.abs(mid.x - lastX) < density*(mid.width()*0.75f - flex)); + mid.y = bottom - mid.height() + Random.Float(mid.height()/2f, mid.height())/density; + mid.angle = Random.Float(-20, 20); + + mids2.add(mid); + mids2Layer.add(mid); + + bottom = mid.y + mid.height(); + lastX = mid.x; + } + } + + //*** Small front layer logic *** + + private static final float[] INIT_SMALL_CHANCES = {1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2}; + private static float[] small_chances = INIT_SMALL_CHANCES.clone(); + + public RectF getSmallFrame(){ + + int tile = Random.chances(small_chances); + if (tile == -1){ + small_chances = INIT_SMALL_CHANCES.clone(); + tile = Random.chances(small_chances); + } + small_chances[tile]--; + + return SMALL_FILM.get(tile); + } + + private void updateFrontLayer(float scale, float shift){ + float bottom = 0; + float lastX = 0; + + for (Image small : smalls){ + small.y -= shift; + if (small.y + small.height() < -20){ + toMove.add(small); + } else if (small.y + small.height() > bottom){ + bottom = small.y + small.height(); + lastX = small.x; + } + } + + if (!toMove.isEmpty()){ + for (Image small : toMove){ + small.frame(getSmallFrame()); + float flex = 0; + do { + small.x = Random.Float(-small.width()/3f, width - 2*small.width()/3f); + flex += 1; + } while (Math.abs(small.x - lastX) < density*(small.width() - flex)); + small.y = bottom - small.height() + Random.Float(small.height()/2f, small.height())/density; + small.angle = Random.Float(-20, 20); + bottom = small.y + small.height(); + lastX = small.x; + } + toMove.clear(); + } + + //smalls are ~115 tall, add a bit for safety + float padding = 150 - (150/2f / density); + while (bottom < (height + padding)){ + Image small = new Image(Assets.Splashes.Title.FRONT_SMALL); + small.frame(getSmallFrame()); + small.scale.set(scale * Random.Float(1.75f, 2.25f)); + + float flex = 0; + do { + small.x = Random.Float(-small.width()/3f, width - 2*small.width()/3f); + flex += 1; + } while (Math.abs(small.x - lastX) < density*(small.width() - flex)); + small.y = bottom - small.height() + Random.Float(small.height()/2f, small.height())/density; + small.angle = Random.Float(-20, 20); + + smalls.add(small); + smallLayer.add(small); + + bottom = small.y + small.height(); + lastX = small.x; + } + } + +} From 7dbb71367b4ee294fe934799225793f29fedb172 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Wed, 10 Sep 2025 13:30:06 -0400 Subject: [PATCH 10/62] v3.2.4: updated list of iOS devices --- .../ios/IOSLauncher.java | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSLauncher.java b/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSLauncher.java index 8e5d48a37..f19f02900 100644 --- a/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSLauncher.java +++ b/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSLauncher.java @@ -125,6 +125,16 @@ public class IOSLauncher extends IOSApplication.Delegate { config.addIosDevice("IPHONE_15_PLUS", "iPhone15,5", 460); config.addIosDevice("IPHONE_15_PRO", "iPhone16,1", 460); config.addIosDevice("IPHONE_15_PRO_MAX", "iPhone16,2", 460); + config.addIosDevice("IPHONE_16_PRO", "iPhone17,1", 460); + config.addIosDevice("IPHONE_16_PRO_MAX", "iPhone17,2", 458); + config.addIosDevice("IPHONE_16", "iPhone17,3", 460); + config.addIosDevice("IPHONE_16_PLUS", "iPhone17,4", 460); + config.addIosDevice("IPHONE_16E", "iPhone17,5", 460); + //TODO these four are guesses, machine strings may be incorrect, PPIs are correct or almost-correct though + config.addIosDevice("IPHONE_17_PRO", "iPhone18,1", 460); + config.addIosDevice("IPHONE_17_PRO_MAX", "iPhone18,2", 460); + config.addIosDevice("IPHONE_AIR", "iPhone18,3", 460); + config.addIosDevice("IPHONE_17", "iPhone18,4", 460); config.addIosDevice("IPAD_7G_WIFI", "iPad7,11", 264); config.addIosDevice("IPAD_7G_WIFI_CELLULAR", "iPad7,12", 264); @@ -144,16 +154,32 @@ public class IOSLauncher extends IOSApplication.Delegate { config.addIosDevice("IPAD_PRO_11_3G", "iPad13,7", 264); config.addIosDevice("IPAD_PRO_12.9_5G", "iPad13,8", 264); config.addIosDevice("IPAD_PRO_12.9_5G", "iPad13,9", 264); - config.addIosDevice("IPAD_PRO_12.9_5G", "iPad13,10", 264); - config.addIosDevice("IPAD_PRO_12.9_5G", "iPad13,11", 264); - config.addIosDevice("IPAD_AIR_5G_WIF", "iPad13,16", 264); - config.addIosDevice("IPAD_AIR_5G_WIFI_CELLULAR", "iPad13,17", 264); - config.addIosDevice("IPAD_10G", "iPad13,18", 264); - config.addIosDevice("IPAD_10G", "iPad13,19", 264); + config.addIosDevice("IPAD_PRO_12.9_5G", "iPad13,10",264); + config.addIosDevice("IPAD_PRO_12.9_5G", "iPad13,11",264); + config.addIosDevice("IPAD_AIR_5G_WIFI", "iPad13,16",264); + config.addIosDevice("IPAD_AIR_5G_WIFI_CELLULAR", "iPad13,17",264); + config.addIosDevice("IPAD_10G", "iPad13,18",264); + config.addIosDevice("IPAD_10G", "iPad13,19",264); config.addIosDevice("IPAD_PRO_11_4G", "iPad14,3", 264); config.addIosDevice("IPAD_PRO_11_4G", "iPad14,4", 264); config.addIosDevice("IPAD_PRO_12.9_6G", "iPad14,5", 264); config.addIosDevice("IPAD_PRO_12.9_6G", "iPad14,6", 264); + config.addIosDevice("IPAD_AIR_11_6G_WIFI", "iPad14,8", 264); + config.addIosDevice("IPAD_AIR_11_6G_WIFI_CELLULAR", "iPad14,9", 264); + config.addIosDevice("IPAD_AIR_13_6G_WIFI", "iPad14,10",264); + config.addIosDevice("IPAD_AIR_13_6G_WIFI_CELLULAR", "iPad14,11",264); + config.addIosDevice("IPAD_AIR_11_7G_WIFI", "iPad15,3", 264); + config.addIosDevice("IPAD_AIR_11_7G_WIFI_CELLULAR", "iPad15,4", 264); + config.addIosDevice("IPAD_AIR_13_7G_WIFI", "iPad15,5", 264); + config.addIosDevice("IPAD_AIR_13_7G_WIFI_CELLULAR", "iPad15,6", 264); + config.addIosDevice("IPAD_11G_WIFI", "iPad15,7", 264); + config.addIosDevice("IPAD_11G_WIFI_CELLULAR", "iPad15,8", 264); + config.addIosDevice("IPAD_MINI_7G_WIFI", "iPad16,1", 326); + config.addIosDevice("IPAD_MINI_7G_WIFI_CELLULAR", "iPad16,2", 326); + config.addIosDevice("IPAD_PRO_11_5G", "iPad16,3", 264); + config.addIosDevice("IPAD_PRO_11_5G", "iPad16,4", 264); + config.addIosDevice("IPAD_PRO_12.9_7G", "iPad16,5", 264); + config.addIosDevice("IPAD_PRO_12.9_7G", "iPad16,6", 264); return new IOSApplication(new ShatteredPixelDungeon(new IOSPlatformSupport()), config); } From 20ee2145e556ab962f5f8d1bfd48b7ade26e9db8 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 11 Sep 2025 10:46:06 -0400 Subject: [PATCH 11/62] v3.2.4: improvements to new title BG based on feedback from Aleks --- .../ui/TitleBackground.java | 237 +++++++++++++++--- 1 file changed, 203 insertions(+), 34 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java index 7b6840df5..7803e0515 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java @@ -33,6 +33,10 @@ import com.watabou.utils.RectF; import java.util.ArrayList; +//TODO still a couple of refinements here: +// now that all assets have 2x layers there's a lot of copypasta, surely logic can be shared in more places +// asset picking isn't ideal, more sophisticated algorithm should help with this +// back layers are dark, which works well on desktop but may be hard to see on mobile public class TitleBackground extends Component { public static float SCROLL_SPEED = 15f; @@ -49,6 +53,14 @@ public class TitleBackground extends Component { private static ArrayList clusters; private static Group clusterLayer; + private static ArrayList clustersFar; + private static Group clustersFarLayer; + + //Small far layer + private static TextureFilm SMALL_FILM = new TextureFilm(Assets.Splashes.Title.FRONT_SMALL, 112, 116); + private static ArrayList smallFars; + private static Group smallFarLayer; + //Mixed Item middle layer 1 private static TextureFilm MID_FILM = new TextureFilm(Assets.Splashes.Title.MID_MIXED, 273, 242); private static ArrayList mids1; @@ -58,9 +70,8 @@ public class TitleBackground extends Component { private static Group mids2Layer; //Small Item front layer - private static TextureFilm SMALL_FILM = new TextureFilm(Assets.Splashes.Title.FRONT_SMALL, 112, 116); - private static ArrayList smalls; - private static Group smallLayer; + private static ArrayList smallCloses; + private static Group smallCloseLayer; private static boolean wasLandscape; private static float oldBaseScale = 1; @@ -69,9 +80,10 @@ public class TitleBackground extends Component { public static void reset(){ archs = null; clusters = null; + smallFars = null; mids1 = null; mids2 = null; - smalls = null; + smallCloses = null; } public TitleBackground(int width, int height){ @@ -91,10 +103,12 @@ public class TitleBackground extends Component { //we reset in this case as scale changes if (archs != null && (landscape != wasLandscape)){ archs = null; + clustersFar = null; clusters = null; + smallFarLayer = null; mids1 = null; mids2 = null; - smalls = null; + smallCloses = null; } wasLandscape = landscape; @@ -121,6 +135,14 @@ public class TitleBackground extends Component { density = width / (800f * scale); density = (density+0.5f)/1.5f; //pull density 33% of the way toward 1 if it is beyond it + clustersFarLayer = new Group(); + if (clustersFar == null) { + clustersFar = new ArrayList<>(); + } else { + convertFloatingLayer(clustersFar, clustersFarLayer, scale, oldWidth); + } + add(clustersFarLayer); + clusterLayer = new Group(); if (clusters == null) { clusters = new ArrayList<>(); @@ -129,6 +151,14 @@ public class TitleBackground extends Component { } add(clusterLayer); + smallFarLayer = new Group(); + if (smallFars == null){ + smallFars = new ArrayList<>(); + } else { + convertFloatingLayer(smallFars, smallFarLayer, scale, oldWidth); + } + add(smallFarLayer); + mids1Layer = new Group(); if (mids1 == null){ mids1 = new ArrayList<>(); @@ -145,13 +175,13 @@ public class TitleBackground extends Component { } add(mids2Layer); - smallLayer = new Group(); - if (smalls == null){ - smalls = new ArrayList<>(); + smallCloseLayer = new Group(); + if (smallCloses == null){ + smallCloses = new ArrayList<>(); } else { - convertFloatingLayer(smalls, smallLayer, scale, oldWidth); + convertFloatingLayer(smallCloses, smallCloseLayer, scale, oldWidth); } - add(smallLayer); + add(smallCloseLayer); oldWidth = width/scale; if (!landscape){ @@ -180,16 +210,14 @@ public class TitleBackground extends Component { protected void convertArchLayer(ArrayList layerList, Group layerGroup, float newBaseScale){ ArrayList oldImages = new ArrayList<>(layerList); layerList.clear(); - float rightMost = 0; for (int i = 0; i < oldImages.size(); i++){ Image oldArch = oldImages.get(i); Image newArch = convertImage(oldArch, newBaseScale); layerList.add(newArch); layerGroup.add(newArch); - rightMost = Math.max(rightMost, newArch.x + newArch.width()); //if we're at the end of a row and haven't hit the end yet, add more archs! while (newArch.x+newArch.width() < width - && (i == oldImages.size()-1 || oldImages.get(i+1).y > oldArch.y)){ + && (i == oldImages.size()-1 || oldImages.get(i+1).y != oldArch.y)){ Image extraArch = new Image(Assets.Splashes.Title.ARCHS); extraArch.frame(getArchFrame()); extraArch.scale.set(newBaseScale); @@ -228,18 +256,25 @@ public class TitleBackground extends Component { float scale = height / 450f; float shift = Game.elapsed * SCROLL_SPEED * scale; + if (width <= height){ + shift /= 1.5f; + } updateArchLayer(scale, shift); if (width <= height){ scale /= 1.5f; } - shift *= 2f; + shift *= 1.33f; + updateClusterFarLayer(scale, shift); + shift *= 1.5f; updateClusterLayer(scale, shift); - shift *= 1.5f; + shift *= 1.33f; + updateFarSmallLayer(scale, shift); + shift *= 1.33f; updateMid1Layer(scale, shift); - shift *= 1.5f; + shift *= 1.33f; updateMid2Layer(scale, shift); - shift *= 1.5f; - updateFrontLayer(scale, shift); + shift *= 1.33f; + updateFrontSmallLayer(scale, shift); } @@ -286,7 +321,7 @@ public class TitleBackground extends Component { //if we aren't low enough, add more arch layers while (bottom < height){ - float left = archs.isEmpty() ? -Random.IntRange(5, 100) : archs.get(0).x; + float left = -5 + (-33.334f * Random.Int(1, 9) * scale); while (left < width){ Image arch = new Image(Assets.Splashes.Title.ARCHS); arch.frame(getArchFrame()); @@ -319,6 +354,61 @@ public class TitleBackground extends Component { return CLUSTER_FILM.get(tile); } + private void updateClusterFarLayer(float scale, float shift){ + float bottom = 0; + float lastX = 0; + + for (Image cluster : clustersFar){ + cluster.y -= shift; + if (cluster.y + cluster.height() < -20){ + toMove.add(cluster); + } else if (cluster.y + cluster.height() > bottom){ + bottom = cluster.y + cluster.height(); + lastX = cluster.x; + } + } + + if (!toMove.isEmpty()){ + for (Image cluster : toMove){ + cluster.frame(getClusterFrame()); + float flex = 0; + do { + cluster.x = Random.Float(-cluster.width()/3f, width - 2*cluster.width()/3f); + flex += 1; + } while (Math.abs(cluster.x - lastX) < density*(cluster.width()/2f - flex)); + cluster.y = bottom - cluster.height() + Random.Float(cluster.height()/2f, cluster.height())/density; + cluster.angle = Random.Float(-20, 20); + bottom = cluster.y + cluster.height(); + lastX = cluster.x; + } + toMove.clear(); + } + + //clusters are 250 tall, add a bit for safety + float padding = 300 - (300/2f / density); + while (bottom < (height + padding)){ + Image cluster = new Image(Assets.Splashes.Title.BACK_CLUSTERS); + cluster.frame(getClusterFrame()); + cluster.scale.set(scale * 0.5f); + + float flex = 0; + do { + cluster.x = Random.Float(-cluster.width()/3f, width - 2*cluster.width()/3f); + flex += 1; + } while (Math.abs(cluster.x - lastX) < density*(cluster.width()/2f - flex)); + cluster.y = bottom - cluster.height() + Random.Float(cluster.height()/2f, cluster.height())/density; + cluster.angle = Random.Float(-20, 20); + + cluster.brightness(0.5f); + + clustersFar.add(cluster); + clustersFarLayer.add(cluster); + + bottom = cluster.y + cluster.height(); + lastX = cluster.x; + } + } + private void updateClusterLayer(float scale, float shift){ float bottom = 0; float lastX = 0; @@ -376,18 +466,28 @@ public class TitleBackground extends Component { //*** Mid layer (1 and 2) logic *** - private static final float[] INIT_MID_CHANCES = {1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; + private static final float[] INIT_MID_CHANCES = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; private static float[] mid_chances = INIT_MID_CHANCES.clone(); + private static ArrayList lastMids = new ArrayList<>(); + public RectF getMidFrame(){ - int tile = Random.chances(mid_chances); - if (tile == -1){ - mid_chances = INIT_MID_CHANCES.clone(); + int tile = -1; + do { tile = Random.chances(mid_chances); - } + if (tile == -1) { + mid_chances = INIT_MID_CHANCES.clone(); + tile = Random.chances(mid_chances); + } + } while (lastMids.contains(tile)); mid_chances[tile]--; + lastMids.add(0, tile); + if (lastMids.size() >= 20){ + lastMids.remove(19); + } + return MID_FILM.get(tile); } @@ -408,6 +508,7 @@ public class TitleBackground extends Component { if (!toMove.isEmpty()){ for (Image mid : toMove){ mid.frame(getMidFrame()); + mid.scale.set(scale * Random.Float(0.75f, 1.25f)); float flex = 0; do { mid.x = Random.Float(-mid.width()/3f, width - 2*mid.width()/3f); @@ -427,6 +528,7 @@ public class TitleBackground extends Component { Image mid = new Image(Assets.Splashes.Title.MID_MIXED); mid.frame(getMidFrame()); mid.scale.set(scale * Random.Float(0.75f, 1.25f)); + mid.brightness(0.9f); float flex = 0; do { @@ -461,6 +563,7 @@ public class TitleBackground extends Component { if (!toMove.isEmpty()){ for (Image mid : toMove){ mid.frame(getMidFrame()); + mid.scale.set(scale * Random.Float(1.25f, 1.75f)); float flex = 0; do { mid.x = Random.Float(-mid.width()/3f, width - 2*mid.width()/3f); @@ -499,26 +602,91 @@ public class TitleBackground extends Component { //*** Small front layer logic *** - private static final float[] INIT_SMALL_CHANCES = {1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2}; + private static final float[] INIT_SMALL_CHANCES = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; private static float[] small_chances = INIT_SMALL_CHANCES.clone(); + private static ArrayList lastSmalls = new ArrayList<>(); + public RectF getSmallFrame(){ - int tile = Random.chances(small_chances); - if (tile == -1){ - small_chances = INIT_SMALL_CHANCES.clone(); + int tile = -1; + do { tile = Random.chances(small_chances); - } + if (tile == -1) { + small_chances = INIT_SMALL_CHANCES.clone(); + tile = Random.chances(small_chances); + } + } while (lastSmalls.contains(tile)); small_chances[tile]--; + lastSmalls.add(0, tile); + if (lastSmalls.size() >= 15){ + lastSmalls.remove(14); + } + return SMALL_FILM.get(tile); } - private void updateFrontLayer(float scale, float shift){ + private void updateFarSmallLayer(float scale, float shift) { float bottom = 0; float lastX = 0; - for (Image small : smalls){ + for (Image small : smallFars) { + small.y -= shift; + if (small.y + small.height() < -20) { + toMove.add(small); + } else if (small.y + small.height() > bottom) { + bottom = small.y + small.height(); + lastX = small.x; + } + } + + if (!toMove.isEmpty()) { + for (Image small : toMove) { + small.frame(getSmallFrame()); + small.scale.set(scale * Random.Float(0.75f, 1.25f)); + float flex = 0; + do { + small.x = Random.Float(small.width() / 3f, width - 4 * small.width() / 3f); + flex += 1; + } while (Math.abs(small.x - lastX) < density * (small.width() - flex)); + small.y = bottom - small.height()/2f + Random.Float(small.height() / 2f, small.height()) / density; + small.angle = Random.Float(-20, 20); + bottom = small.y + small.height(); + lastX = small.x; + } + toMove.clear(); + } + + //smalls are ~115 tall, add a bit for safety + float padding = 150 - (150 / 2f / density); + while (bottom < (height + padding)) { + Image small = new Image(Assets.Splashes.Title.FRONT_SMALL); + small.frame(getSmallFrame()); + small.scale.set(scale * Random.Float(0.75f, 1.25f)); + small.brightness(0.8f); + + float flex = 0; + do { + small.x = Random.Float(small.width() / 3f, width - 4 * small.width() / 3f); + flex += 1; + } while (Math.abs(small.x - lastX) < density * (small.width() - flex)); + small.y = bottom - small.height()/2f + Random.Float(small.height() / 2f, small.height()) / density; + small.angle = Random.Float(-20, 20); + + smallFars.add(small); + smallFarLayer.add(small); + + bottom = small.y + small.height(); + lastX = small.x; + } + } + + private void updateFrontSmallLayer(float scale, float shift){ + float bottom = 0; + float lastX = 0; + + for (Image small : smallCloses){ small.y -= shift; if (small.y + small.height() < -20){ toMove.add(small); @@ -531,6 +699,7 @@ public class TitleBackground extends Component { if (!toMove.isEmpty()){ for (Image small : toMove){ small.frame(getSmallFrame()); + small.scale.set(scale * Random.Float(2f, 2.5f)); float flex = 0; do { small.x = Random.Float(-small.width()/3f, width - 2*small.width()/3f); @@ -549,7 +718,7 @@ public class TitleBackground extends Component { while (bottom < (height + padding)){ Image small = new Image(Assets.Splashes.Title.FRONT_SMALL); small.frame(getSmallFrame()); - small.scale.set(scale * Random.Float(1.75f, 2.25f)); + small.scale.set(scale * Random.Float(2f, 2.5f)); float flex = 0; do { @@ -559,8 +728,8 @@ public class TitleBackground extends Component { small.y = bottom - small.height() + Random.Float(small.height()/2f, small.height())/density; small.angle = Random.Float(-20, 20); - smalls.add(small); - smallLayer.add(small); + smallCloses.add(small); + smallCloseLayer.add(small); bottom = small.y + small.height(); lastX = small.x; From 342f242ce6a37fa444c3f315142600e73495791b Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 11 Sep 2025 11:11:06 -0400 Subject: [PATCH 12/62] v3.2.4: updated version, changelog, and translations for v3.2.4! --- build.gradle | 4 +- .../messages/actors/actors_nl.properties | 2 +- .../messages/actors/actors_tr.properties | 40 +++++++++---------- .../assets/messages/items/items.properties | 2 +- .../assets/messages/items/items_fr.properties | 4 +- .../assets/messages/items/items_nl.properties | 12 +++--- .../assets/messages/items/items_vi.properties | 10 ++--- .../assets/messages/items/items_zh.properties | 4 +- .../messages/journal/journal_ru.properties | 2 +- .../assets/messages/misc/misc_zh.properties | 2 +- .../ui/changelist/v3_X_Changes.java | 25 ++++++++++++ 11 files changed, 66 insertions(+), 41 deletions(-) diff --git a/build.gradle b/build.gradle index 537d8bea7..349da3a6c 100644 --- a/build.gradle +++ b/build.gradle @@ -14,8 +14,8 @@ allprojects { appName = 'Shattered Pixel Dungeon' appPackageName = 'com.shatteredpixel.shatteredpixeldungeon' - appVersionCode = 868 - appVersionName = '3.2.3' + appVersionCode = 874 + appVersionName = '3.2.4' appJavaCompatibility = JavaVersion.VERSION_11 diff --git a/core/src/main/assets/messages/actors/actors_nl.properties b/core/src/main/assets/messages/actors/actors_nl.properties index 3c0c01a5c..abebd42c4 100644 --- a/core/src/main/assets/messages/actors/actors_nl.properties +++ b/core/src/main/assets/messages/actors/actors_nl.properties @@ -353,7 +353,7 @@ actors.buffs.physicalempower.name=fysiek versterkt actors.buffs.physicalempower.desc=Je slagen zijn versterkt, waardoor je meer schade kunt aanrichten met fysieke aanvallen.\n\nBonusschade: %1$d.\nResterende treffers: %2$d. actors.buffs.pincushion.name=speldenkussen -actors.buffs.pincushion.desc=De werpwapens die je naar dit personage heb gegooid zijn op het moment aan hen vastgeplakt en valt op de grond nadat het karakter is verslagen.\n\nDe volgende voorwerpen zitten op het moment vast: +actors.buffs.pincushion.desc=De werpwapens die je naar dit personage heb gegooid zijn op het moment aan hen vastgeplakt en vallen op de grond nadat het karakter is verslagen.\n\nDe volgende voorwerpen zitten op het moment vast: actors.buffs.poison.name=vergiftigd actors.buffs.poison.heromsg=Je bent vergiftigd! diff --git a/core/src/main/assets/messages/actors/actors_tr.properties b/core/src/main/assets/messages/actors/actors_tr.properties index 83b232a70..f68ce9db8 100644 --- a/core/src/main/assets/messages/actors/actors_tr.properties +++ b/core/src/main/assets/messages/actors/actors_tr.properties @@ -422,21 +422,21 @@ actors.buffs.terror.desc=Terör, hedefini kontrol dışı bir paniğe sokan mani actors.buffs.toxicimbue.name=zehirle yoğrulmuş actors.buffs.toxicimbue.desc=Zehirli enerjiyle dolusun!\n\nEtrafınızda hareket ettikçe zehirli gaz sürekli olarak sizden yayılacak ve düşmanlarınıza zarar verecek. Etki süresi boyunca ve sonrasında birkaç tur boyunca zehirli gaza ve zehre karşı bağışıklığınız vardır.\n\nKalan zehir enerjisi tur sayısı: %s. -actors.buffs.corrosion.name=aşındırma +actors.buffs.corrosion.name=Aşınma actors.buffs.corrosion.heromsg=Eriyorsun! actors.buffs.corrosion.ondeath=Eriyip gittin... actors.buffs.corrosion.rankings_desc=Eridi actors.buffs.corrosion.desc=Güçlü asit eti, metali ve kemiği endişelendirici bir hızda eritir.\n\nAşındırma hasarı hedef erimeye devam ettikçe zamanla artar.\n\nAşındırmanın geçmesine kalan sıra: %1$s.\nŞu anki aşınma hasarı:%2$d. -actors.buffs.vertigo.name=baş dönmesi +actors.buffs.vertigo.name=Baş Dönmesi actors.buffs.vertigo.desc=Düz bir yolda yürümek tüm dünya dönerken zor olabilir.\n\nBaş dönmesinin etkisi altında olan bir karakter gitmeye çalıştığı yer yerine rastgele başka bir yere gidecektir.\n\nBaş dönmesinin geçmesine kalan sıra: %s. -actors.buffs.wandempower.name=asalar güçlendi +actors.buffs.wandempower.name=Asalsr Güçlendi actors.buffs.wandempower.desc=Hasar veren asaların güçlendirildi, bir kaç vuruş için verilen hasar miktarı arttı.\n\nEk hasar:%1$d.\nKalan vuruşlar:%2$d. actors.buffs.weakness.name=Güçsüzleşmiş actors.buffs.weakness.heromsg=Zayıflamış hissediyorsun! -actors.buffs.weakness.desc=Her şey bir anda daha ağır hissettirmeye başladı.\n\nZayıflatma büyüsü karakterin fiziksel gücünü azaltır, ve 33%% daha az hasar vermelerine sebep olur.\n\nzayıflamanın geçmesine kalan tur.%s. +actors.buffs.weakness.desc=Her şey bir anda daha ağır hissettirmeye başladı.\n\nGüçsüzleşme büyüsü karakterin fiziksel gücünü azaltır, ve 33%% daha az hasar vermelerine sebep olur.\n\nGüçsüzleşmenin geçmesine kalan tur.%s. actors.buffs.wellfed.name=tok actors.buffs.wellfed.desc=Gayet tatmin olmuş ve tok hissediyorsun.\n\nİyi beslenmişken açlığın artmaz, ve bunun yanında ekstra bir miktar sağlığa sahip olursun.\n\nKalan sıra: %d. @@ -464,7 +464,7 @@ actors.hero.abilities.warrior.endure$enduretracker.desc=Savaşçı şu an katlan actors.hero.abilities.warrior.endure.short_desc=Savaşçı _Katlanırken_, birkaç tur atlar ama fazladan hasar direnci kazanır. Sonra katlandığı hasara göre fazladan hasar verir. actors.hero.abilities.warrior.endure.desc=Savaşçı, tüm kaynaklardan yarı hasar alarak 3 tur katlanır. Bu azalma, zırh gibi hasara dayanıklı etkilerden önce uygulanır.\n\nKatlandıktan sonra, savaşçının 10 sıra içindeki bir sonraki vuruşu ilave hasar kazanır. Bu fazlandan hasar, herhangi bir hasar azaltma etkisinden önce, ona verilen tüm hasarın yarısına eşittir!\n\nSavaşçının herhangi bir kombosu varsa, bu yeteneği kullanmak kombonun kalan süresini 3 tur artırır. -actors.hero.abilities.mage.elementalblast.name=elemental patlama +actors.hero.abilities.mage.elementalblast.name=Elemental Patlama actors.hero.abilities.mage.elementalblast.no_staff=Bu yeteneği asanız olmadan kullanamazsınız. actors.hero.abilities.mage.elementalblast.short_desc=Büyücü asasından bir _Elemental Patlama_ yayar, değneğindeki asaya bağlı olarak değişen bir etkiyle etrafındaki geniş bir alanı kaplar. actors.hero.abilities.mage.elementalblast.desc=Büyücü, en fazla 4 kare uzağa kadar dairesel bir bölgeyi kaplayan ve 15-25'e kadar hasar veren bir büyü patlaması yayar. Elemental patlamanın özel etkisi, Büyücünün değneğine yerleştirilen asaya göre değişecektir. @@ -473,36 +473,36 @@ actors.hero.abilities.mage.wildmagic.name=vahşi büyü actors.hero.abilities.mage.wildmagic.no_wands=Saldıracak bir asanız yok! actors.hero.abilities.mage.wildmagic.short_desc=Büyücü, asalarında bulunan _Vahşi Büyü_'yü serbest bırakır ve bunları tek bir tur boyunca seçilen bir hedefe gelişigüzel olarak birden çok kez ateşler. actors.hero.abilities.mage.wildmagic.desc=Büyücü asalarındaki gücü açığa çıkarır ve tek bir turda 4 defaya kadar gelişigüzel ateşler. Büyücünün asası bu etkiye dahil değildir.\n\nAyrıca her asanın seviyesi 2 artırılarak +3'e çıkarılır. Bu yetenek her bir vuruş için yarım asa şarjı kullanır ve hiçbir asa 2 kezden fazla ateşlenemez. -actors.hero.abilities.mage.warpbeacon.name=ışınlanma feneri -actors.hero.abilities.mage.warpbeacon.depths=Farklı katlar arasında ışınlanamazsın! +actors.hero.abilities.mage.warpbeacon.name=Işınlanma Feneri +actors.hero.abilities.mage.warpbeacon.depths=Katlar arası ışınlanamazsın! actors.hero.abilities.mage.warpbeacon.locked_floor=Kilitli bir katı terk edemezsin! actors.hero.abilities.mage.warpbeacon.too_far=O konum çok uzakta! actors.hero.abilities.mage.warpbeacon.invalid_beacon=Oraya bir fener koyamazsın! -actors.hero.abilities.mage.warpbeacon.window_desc=Fenerin şu anda kat %d de yerleştirilmiş. -actors.hero.abilities.mage.warpbeacon.window_tele=fenere ışınlan -actors.hero.abilities.mage.warpbeacon.window_clear=feneri sıfırla -actors.hero.abilities.mage.warpbeacon.window_cancel=iptal et +actors.hero.abilities.mage.warpbeacon.window_desc=Fenerin şu anda kat %d'de yerleştirilmiş. +actors.hero.abilities.mage.warpbeacon.window_tele=Fenere Işınlan +actors.hero.abilities.mage.warpbeacon.window_clear=Feneri Sıfırla +actors.hero.abilities.mage.warpbeacon.window_cancel=İptal Et actors.hero.abilities.mage.warpbeacon.short_desc=Büyücü mevcut konumuna bir _Işınlanma Feneri_ koyar, daha sonra ona anında ışınlanabilir. actors.hero.abilities.mage.warpbeacon.desc=Büyücü, istediği zaman ışınlanabileceği bir fener yerleştirir. Feneri yerleştirmek 1 tur alır, ama ışınlanmak anında gerçekleşir.\n\nBüyücü varsayılan olarak katlar arası ışınlanamaz, veya feneri ulaşılamaz yerlere, mesela kilitli odalara, ulaşmak için kullanamaz. Büyücü düşmanların içine ışınlanabilir, bu, düşmanları yana itecektir. -actors.hero.abilities.rogue.smokebomb.name=sis bombası +actors.hero.abilities.rogue.smokebomb.name=Sis Bombası actors.hero.abilities.rogue.smokebomb.fov=Sadece görüş alanındaki boş bir bölgeye atlayabilirsin. actors.hero.abilities.rogue.smokebomb.prompt=Atlayacağın yeri seç -actors.hero.abilities.rogue.smokebomb$ninjalog.name=tahta kukla +actors.hero.abilities.rogue.smokebomb$ninjalog.name=Tahta Kukla actors.hero.abilities.rogue.smokebomb$ninjalog.desc=Her nasılsa, düşmanlar bu tahta kuklanın gerçek Haydut olduğuna kolayca ikna oluyor! actors.hero.abilities.rogue.smokebomb$ninjalog.discover_hint=Bu karakteri, belirli bir kahraman zırh yeteneğiyle bulabilirsin. actors.hero.abilities.rogue.smokebomb.short_desc=Haydut, bir _Sis Bombası_ atar ve bu sırada anında uzağa atılır. Eski yerine yakın düşmanları kör eder. actors.hero.abilities.rogue.smokebomb.desc=Haydut bir sis bombası atar ve 6 kare uzaklığa kadar anında atılır. Tehlikelerin ve düşmanların içinden atılabilir, ama duvar gibi sağlam arazinin içinden geçemez\n\nHaydut'un eski konumuna yakın olan düşmanlar 5 tur boyunca kör olur. -actors.hero.abilities.rogue.deathmark.name=ölüm işareti -actors.hero.abilities.rogue.deathmark.ally_target=Sadece düşmanları işaretleyebilirsin +actors.hero.abilities.rogue.deathmark.name=Ölüm Damgası +actors.hero.abilities.rogue.deathmark.ally_target=Sadece düşmanları damgalayabilirsin actors.hero.abilities.rogue.deathmark.short_desc=Haydut, seçilen bir düşmanın üzerine bir _Ölüm İşareti_ koyar. İşaretlenen düşmanlar ilave hasar alır, ama işaret sonlanana kadar ölemezler. -actors.hero.abilities.rogue.deathmark.desc=Haydut, seçilen bir düşmanın üzerine bir işaret koyar, onun %25 ilave hasar almasını sağlar. İşaret anında uygulanır ve 5 tur boyunca sürer.\n\nİşaretlenen düşmanlar ilave hasar alır ama işaret sona erene kadar ölemezler. Eğer bir düşman 0 HP iken işaret sona ererse, düşman anında ölür. -actors.hero.abilities.rogue.deathmark$deathmarktracker.name=ölümle işaretlenmiş -actors.hero.abilities.rogue.deathmark$deathmarktracker.desc=Bu düşman işaretlenmiş, düşmanın 25%% ilave hasar almasına sebep olur, ama işaret sona erene kadar ölemez.\n\nKalan tur: %s -actors.hero.abilities.rogue.shadowclone.name=gölge klon +actors.hero.abilities.rogue.deathmark.desc=Haydut, seçilen bir düşmanın üzerine bir damga koyar, onun %25 ilave hasar almasını sağlar. damga anında koyulur ve 5 tur sürer.\n\nDamgalanan düşmanlar ilave hasar alır ancak damga sona erene kadar ölemezler. Eğer bir düşman 0 SP'de iken damga sona ererse anında ölür. +actors.hero.abilities.rogue.deathmark$deathmarktracker.name=Ölüm Damgalı +actors.hero.abilities.rogue.deathmark$deathmarktracker.desc=Bu düşman damgalı. Bu, düşmanın 25%% ilave hasar almasına sebep olur, ama damga sona erene kadar ölemez.\n\nKalan tur: %s +actors.hero.abilities.rogue.shadowclone.name=Gölge Klon actors.hero.abilities.rogue.shadowclone.short_desc=Haydut, savaşta kendisine yardım etmesi için yönlendirilebilen bir _Gölge Klon_ çağırır. actors.hero.abilities.rogue.shadowclone.desc=Haydut, savaşta kendisine yardım etmesi için yönlendirilebilen, kendisinin gölgeli bir taklidini çağırır. Gölge klonu yönlendirmek yük gerektirmez\n\nKlonun 80 HP'si vardır, zırhı yoktur ve 10-20 hasar verir. Tüm bu özellikler yeteneklerle geliştirilebilir, böylece klon kahramanın sahip olduğu zırh ve silahlardan faydalanabilir. -actors.hero.abilities.rogue.shadowclone$shadowally.name=gölge haydut +actors.hero.abilities.rogue.shadowclone$shadowally.name=Gölge Haydudu actors.hero.abilities.rogue.shadowclone$shadowally.direct_defend=Klonun bu konuma gidiyor. actors.hero.abilities.rogue.shadowclone$shadowally.direct_follow=Klonun seni takip ediyor. actors.hero.abilities.rogue.shadowclone$shadowally.direct_attack=Klonun saldırmak için hareket ediyor! diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index 662e240d0..0577e67a7 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -1416,7 +1416,7 @@ items.trinkets.eyeofnewt.typical_stats_desc=Typically this trinket will reduce y items.trinkets.eyeofnewt.stats_desc=At its current level this trinket will reduce your vision range by _%1$s%%_, but will also grant you mind vision on enemies within _%2$d_ tiles. items.trinkets.ferrettuft.name=ferret tuft -items.trinkets.ferrettuft.desc=A tuft of silky white ferret fur, held together by a lime green ribbon tied into a bow. Ferrets are known for their agility, mischievousness, and lack of integrity. Some of that power seems to radiate from the trinket, enhancing the evasion of anything nearby. +items.trinkets.ferrettuft.desc=A tuft of silky white ferret fur, held together by a Lime green ribbon tied into a bow. Ferrets are known for their agility, mischievousness, and lack of integrity. Some of that power seems to radiate from the trinket, enhancing the evasion of anything nearby. items.trinkets.ferrettuft.typical_stats_desc=Typically this trinket will increase the evasion of all characters by _%1$s%%_. items.trinkets.ferrettuft.stats_desc=At its current level this trinket will increase the evasion of all characters by _%1$s%%_. diff --git a/core/src/main/assets/messages/items/items_fr.properties b/core/src/main/assets/messages/items/items_fr.properties index 3b168c1e3..b1c860cc3 100644 --- a/core/src/main/assets/messages/items/items_fr.properties +++ b/core/src/main/assets/messages/items/items_fr.properties @@ -2201,11 +2201,11 @@ items.weapon.missiles.shuriken$shurikeninstanttracker.name=Rechargement des shur items.weapon.missiles.shuriken$shurikeninstanttracker.desc=Vous avez récemment lancé instantanément un shuriken, et devez attendre avant de pouvoir recommencer. Vous pouvez toujours lancer des shurikens, mais à une vitesse normale.\n\nTours restants : %s. items.weapon.missiles.throwingclub.name=bâton de lancer -items.weapon.missiles.throwingclub.stats_desc= +items.weapon.missiles.throwingclub.stats_desc=Cette arme ne s'accroche pas aux ennemis et peut être ramassée instantanément. items.weapon.missiles.throwingclub.desc=Une arme de jet assez simple mais robuste, grossièrement une pierre attachée à un bâton. items.weapon.missiles.throwinghammer.name=marteau de lancer -items.weapon.missiles.throwinghammer.stats_desc= +items.weapon.missiles.throwinghammer.stats_desc=Cette arme ne s'accroche pas aux ennemis et peut être ramassée instantanément. items.weapon.missiles.throwinghammer.desc=Ces lourds marteaux ont été créés pour être lancés sur les ennemis. Leur corps lisse entièrement métallique leur confère une grande durabilité. items.weapon.missiles.throwingknife.name=couteau de lancer diff --git a/core/src/main/assets/messages/items/items_nl.properties b/core/src/main/assets/messages/items/items_nl.properties index 6e174e6e8..a425b6fab 100644 --- a/core/src/main/assets/messages/items/items_nl.properties +++ b/core/src/main/assets/messages/items/items_nl.properties @@ -558,16 +558,16 @@ items.food.blandfruit.name=flauwfruit items.food.blandfruit.cooked=gekookt flauwfruit items.food.blandfruit.sunfruit=zonnefruit items.food.blandfruit.rotfruit=rotfruit -items.food.blandfruit.earthfruit=aardefruit +items.food.blandfruit.earthfruit=aardfruit items.food.blandfruit.blindfruit=blindfruit items.food.blandfruit.firefruit=vuurfruit items.food.blandfruit.icefruit=ijsfruit -items.food.blandfruit.fadefruit=verdwijnfruit -items.food.blandfruit.sorrowfruit=zieligfruit +items.food.blandfruit.fadefruit=vaagfruit +items.food.blandfruit.sorrowfruit=treurfruit items.food.blandfruit.stormfruit=stormfruit items.food.blandfruit.dreamfruit=magefruit items.food.blandfruit.starfruit=sterrenfruit -items.food.blandfruit.swiftfruit=snelfruit +items.food.blandfruit.swiftfruit=fluksfruit items.food.blandfruit.raw=Je durft het niet rauw te eten. items.food.blandfruit.desc=Het is nu zo droog en onbeduidend, dat het misschien zou verbeteren door het te stoven met een ander ingrediënt. items.food.blandfruit.desc_cooked=De vrucht is tijdens het koken in de ketel opgezwollen en heeft zelfs de eigenschappen van het zaad waarmee hij gekookt was geabsorbeerd. Het heeft het effect van de toverdrank waarmee het zaad overeenkwam. @@ -2201,11 +2201,11 @@ items.weapon.missiles.shuriken$shurikeninstanttracker.name=Werpster afkoelperiod items.weapon.missiles.shuriken$shurikeninstanttracker.desc=Je hebt onlangs direct een werpster gegooid en moet wachten voordat je dit opnieuw doet. Werpsterren kunnen nog steeds worden gegooid, maar dan met normale wapensnelheid. \n\nResterende beurten: %s. items.weapon.missiles.throwingclub.name=werpknuppel -items.weapon.missiles.throwingclub.stats_desc= +items.weapon.missiles.throwingclub.stats_desc=Dit wapen blijft niet aan vijanden vastzitten en kan direct verzameld worden. items.weapon.missiles.throwingclub.desc=Een vrij eenvoudig maar duurzaam werpwapen, in feite een grote steen bevestigd aan een stok. items.weapon.missiles.throwinghammer.name=werphamer -items.weapon.missiles.throwinghammer.stats_desc= +items.weapon.missiles.throwinghammer.stats_desc=Dit wapen blijft niet aan vijanden vastzitten en kan direct verzameld worden. items.weapon.missiles.throwinghammer.desc=Deze forse hamers zijn ontworpen om naar een vijand te gooien. Dankzij hun soepele, volledig metalen constructie zijn ze zeer duurzaam. items.weapon.missiles.throwingknife.name=werpmes diff --git a/core/src/main/assets/messages/items/items_vi.properties b/core/src/main/assets/messages/items/items_vi.properties index 01216495b..5fde80ef7 100644 --- a/core/src/main/assets/messages/items/items_vi.properties +++ b/core/src/main/assets/messages/items/items_vi.properties @@ -199,7 +199,7 @@ items.artifacts.cloakofshadows.name=áo choàng bóng tối items.artifacts.cloakofshadows.ac_stealth=TÀNG HÌNH items.artifacts.cloakofshadows.cooldown=Áo choàng của bạn cần %d lượt nữa để nạp lại năng lượng. items.artifacts.cloakofshadows.cursed=Bạn không thể sử dụng một cái áo choàng bị nguyền rủa. -items.artifacts.cloakofshadows.no_charge=Áo choàng của bạn chưa sạc lại đủ để trở nên dùng được. +items.artifacts.cloakofshadows.no_charge=Áo choàng của bạn chưa hồi đủ năng lượng để có thể sử dụng được. items.artifacts.cloakofshadows.desc=Một chiếc áo choàng thần kì vô giá, được lấy trộm từ kho vũ khí hoàng gia nhiều năm trước bởi Kẻ cướp. Khi được mặc, nó có thể được dùng để trở nên hoàn toàn vô hình trong một khoảng thời gian ngắn.\n\nCái áo choàng này càng được sử dụng nhiều, nó sẽ càng mạnh hơn, cho phép Kẻ cướp trở nên vô hình thường xuyên hơn và lâu hơn. items.artifacts.cloakofshadows.discover_hint=Một trong các người hùng bắt đầu với vật phẩm này. items.artifacts.cloakofshadows$cloakstealth.no_charge=Áo choàng của bạn đã hết năng lượng. @@ -440,7 +440,7 @@ items.artifacts.talismanofforesight$foresight.desc=Bạn cảm thấy rất lo n items.artifacts.timekeepershourglass.name=đồng hồ cát của kẻ giữ thời gian items.artifacts.timekeepershourglass.ac_activate=KÍCH HOẠT items.artifacts.timekeepershourglass.deactivate=Bạn hủy kích hoạt "đóng băng thời gian". -items.artifacts.timekeepershourglass.no_charge=Cái đòng hồ cát của bạn vẫn chưa sạc lại đủ để có thể sử dụng được. +items.artifacts.timekeepershourglass.no_charge=Đồng hồ cát của bạn chưa hồi đủ năng lượng để có thể sử dụng được. items.artifacts.timekeepershourglass.cursed=Bạn không thể sử dụng một chiếc đồng hồ cát bị nguyền rủa. items.artifacts.timekeepershourglass.onstasis=Thế giới dường như thay đổi xung quanh bạn ngay lập tức. items.artifacts.timekeepershourglass.onfreeze=Mọi thứ xung bạn bỗng nhiên đóng băng. @@ -491,7 +491,7 @@ items.bags.velvetpouch.desc=Cái túi nhung nhỏ này có thể chứa nhiều items.bags.velvetpouch.discover_hint=Một trong các người hùng bắt đầu với vật phẩm này. items.bags.magicalholster.name=bao da thần kì -items.bags.magicalholster.desc=Cái bao da mảnh mai này được làm từ một loại da động vật lạ, nó sở hữu một phép thuật thần kì giúp nó chứa một lượng vũ khí tầm xa khổng lồ.\n\nBạn có thể dễ dàng thò tay vao trong bao và sẽ luôn lấy được vật phẩm mà bạn tìm.\n\nNhờ phép thuật của cái bao da, các cây đũa phép sẽ sạc lại nhanh hơn một chút và các vũ khí ném sẽ dùng được lâu hơn một chút bên trong nó. +items.bags.magicalholster.desc=Cái bao da mảnh mai này được làm từ một loại da động vật lạ, nó sở hữu một phép thuật thần kì giúp nó chứa một lượng vũ khí tầm xa khổng lồ.\n\nBạn có thể dễ dàng thò tay vao trong bao và sẽ luôn lấy được vật phẩm mà bạn tìm.\n\nNhờ phép thuật của cái bao da, các cây đũa phép sẽ hồi năng lượng nhanh hơn một chút và các vũ khí ném sẽ dùng được lâu hơn một chút bên trong nó. @@ -1129,7 +1129,7 @@ items.scrolls.scrollofrage.name=cuộn giấy thịnh nộ items.scrolls.scrollofrage.roar=Cuộn giấy này phát ra tiếng gầm giận dữ vang vọng khắp hầm ngục! items.scrolls.scrollofrage.desc=Khi được đọc thành tiếng, cuộn giấy này sẽ giải phóng một tiếng gầm lớn, kéo tất cả kẻ địch đến chỗ người đọc, và làm nổi giận những kẻ địch ở gần. -items.scrolls.scrollofrecharging.name=cuộn giấy sạc lại +items.scrolls.scrollofrecharging.name=cuộn giấy hồi năng items.scrolls.scrollofrecharging.surge=Một nguồn năng lượng chạy qua cơ thể bạn, tiếp thêm năng lượng cho các cây đũa phép của bạn! items.scrolls.scrollofrecharging.desc=Sức mạnh phép thuật thô được lưu giữ trong tấm da này sẽ hồi năng lượng cho các cây đũa phép của người sử dụng theo thời gian khi được giải phóng. @@ -1317,7 +1317,7 @@ items.spells.unstablespell.name=thần chú bất ổn items.spells.unstablespell.desc=Tinh thể nhỏ màu đen hình vuông này có những biểu tượng rune biến đổi ở trên mỗi mặt của nó.\n\nKhi được sử dụng, nó sẽ kích hoạt hiệu ứng của một cuộn giấy ngẫu nhiên. Hiệu ứng cuộn giấy sẽ luôn là một hiệu ứng thiên về chiến đấu nếu có kẻ địch trong tầm nhìn của bạn, còn nếu không thì sẽ luôn thiên về không chiến đấu. items.spells.wildenergy.name=năng lượng hỗn loạn -items.spells.wildenergy.desc=Thần chứ này chứa một phần năng lượng bị nguyền, thứ đã giúp DM-300 chạy. Khi sử dụng, nó sẽ sạc lại các đũa phép và cổ vật đang được trang bị của bạn và đồng thời kích hoạt một hiệu ứng đũa phép bị nguyền ngẫu nhiên. Tuy nhiên, bạn sẽ được định hướng nơi mà phép thuật bị nguyền này bắn vào. +items.spells.wildenergy.desc=Thần chứ này chứa một phần năng lượng bị nguyền, thứ đã giúp DM-300 chạy. Khi sử dụng, nó sẽ hồi năng lượng cho các đũa phép và cổ vật đang được trang bị của bạn và đồng thời kích hoạt một hiệu ứng đũa phép bị nguyền ngẫu nhiên. Tuy nhiên, bạn sẽ được định hướng nơi mà phép thuật bị nguyền này bắn vào. ###runestones diff --git a/core/src/main/assets/messages/items/items_zh.properties b/core/src/main/assets/messages/items/items_zh.properties index 5328e4b15..ae1f3219d 100644 --- a/core/src/main/assets/messages/items/items_zh.properties +++ b/core/src/main/assets/messages/items/items_zh.properties @@ -1402,8 +1402,8 @@ items.trinkets.chaoticcenser.stats_desc=在当前等级下,这件饰物会每 items.trinkets.dimensionalsundial.name=位面日晷 items.trinkets.dimensionalsundial.warning=你的日晷不再显影,这使你倍感不安。 items.trinkets.dimensionalsundial.desc=不知为何,这块小型手持式日晷能在地牢深处显影,甚至你不将其摆正也是如此。更奇怪的是,晷影的方位似乎与这个世界的太阳无关。当晷影不再显现时,日晷似乎会招致危险。 -items.trinkets.dimensionalsundial.typical_stats_desc=这件饰物通常会在设备日间(8:00~20:00)降低_%1$d%%_的敌人生成速率并在设备夜间(20:00~8:00)提升_%2$d%%_的敌人生成速率。 -items.trinkets.dimensionalsundial.stats_desc=在当前等级下,这件饰物会在设备日间(8:00~20:00)降低_%1$d%%_的敌人生成速率并在设备夜间(20:00~8:00)提升_%2$d%%_的敌人生成速率。 +items.trinkets.dimensionalsundial.typical_stats_desc=这件饰物通常会在昼间(8:00~20:00)降低_%1$d%%_的敌人生成速率并在夜间(20:00~8:00)提升_%2$d%%_的敌人生成速率。 +items.trinkets.dimensionalsundial.stats_desc=在当前等级下,这件饰物会在昼间(8:00~20:00)降低_%1$d%%_的敌人生成速率并在夜间(20:00~8:00)提升_%2$d%%_的敌人生成速率。 items.trinkets.exoticcrystals.name=奇异能晶 items.trinkets.exoticcrystals.desc=这些小型粉色晶体有着和炼金能量晶体一样的几何外形。尽管它们不能直接为炼金实验供能,但不知为何似乎能影响你找到的药剂和卷轴。 diff --git a/core/src/main/assets/messages/journal/journal_ru.properties b/core/src/main/assets/messages/journal/journal_ru.properties index 4b3b6d616..4e8002723 100644 --- a/core/src/main/assets/messages/journal/journal_ru.properties +++ b/core/src/main/assets/messages/journal/journal_ru.properties @@ -45,7 +45,7 @@ journal.document.adventurers_guide.identifying.body=В каждом подзем journal.document.adventurers_guide.food.title=Береги запасы еды! journal.document.adventurers_guide.food.body=Рационировать еду — один из лучших способов повысить шансы на выживание, ведь необязательно принимать пищу сразу, как только проголодался!\n\nПока вы не голодаете, ваше здоровье постепенно восстанавливается, так что этот эффект будет потрачен впустую, если вы уже полностью здоровы.\n\nЕсли вы будете принимать пищу осознанно, учитывая состояние здоровья, ваших запасов хватит дольше. journal.document.adventurers_guide.alchemy.title=Алхимия и Аксессуары -journal.document.adventurers_guide.alchemy.body=Если вы не находите какой-то предмет полезным, можно использовать его в качестве ингредиента в алхимическом котле или превращены в алхимическую энергию для любых задач. Расщепление зелий и свитков опознаёт их!\n\nАксессуары — это уникальное снаряжение, которое можно изготовить и улучшить только с помощью алхимии. Они могут быть изготовлены из небольшого количества алхимической энергии и магического катализатора.\n\n(Первый алхимический котёл можно найти на 3-м или 4-м этаже подземелья. Рядом с котлами можно найти страницы из книги рецептов по алхимии.) +journal.document.adventurers_guide.alchemy.body=Если вы не находите какой-то предмет полезным, можно использовать его в качестве ингредиента в алхимическом котле или превратить в алхимическую энергию для любых задач. Расщепление зелий и свитков опознаёт их!\n\nАксессуары — это уникальное снаряжение, которое можно изготовить и улучшить только с помощью алхимии. Они могут быть изготовлены из небольшого количества алхимической энергии и магического катализатора.\n\n(Первый алхимический котёл можно найти на 3-м или 4-м этаже подземелья. Рядом с котлами можно найти страницы из книги рецептов по алхимии.) journal.document.adventurers_guide.dieing.title=Принятие поражения journal.document.adventurers_guide.dieing.body=Приключения в подземелье сопряжены с немалым риском, и большинство искателей приключений в итоге настигнет погибель.\n\nУдача важна, но самые опытные искатели приключений это те, которые используют любую уловку, чтобы увеличить свои шансы на выживание.\n\n(Не отчаивайтесь, если вы постоянно погибаете, это сложная игра! Сосредоточьтесь на изучении игры и улучшении своих навыков, не настраивайтесь на быструю победу.) journal.document.adventurers_guide.searching.title=Обыскивай каждый уголок! diff --git a/core/src/main/assets/messages/misc/misc_zh.properties b/core/src/main/assets/messages/misc/misc_zh.properties index 760faf018..59b1a7541 100644 --- a/core/src/main/assets/messages/misc/misc_zh.properties +++ b/core/src/main/assets/messages/misc/misc_zh.properties @@ -208,7 +208,7 @@ badges$badge.many_buffs.title=狂乱的鸡尾酒 badges$badge.many_buffs.desc=同时拥有至少10种增益/减益 badges$badge.pacifist_ascent.title=光荣凯旋 badges$badge.pacifist_ascent.desc=将其诅咒未曾减弱的Yendor护符带出地牢 -badges$badge.taking_the_mick.title=洋相百出 +badges$badge.taking_the_mick.title=弄巧成拙 badges$badge.taking_the_mick.desc=以一把至少20级的镐子对最终boss打出致命一击 challenges.no_food=缩餐节食 diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java index 78e6e9130..c801a4d3b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java @@ -86,6 +86,31 @@ public class v3_X_Changes { changes.hardlight(Window.TITLE_COLOR); changeInfos.add(changes); + changes = new ChangeInfo("v3.2.4", false, null); + changes.hardlight(Window.TITLE_COLOR); + changeInfos.add(changes); + + changes.addButton( new ChangeButton(Icons.get(Icons.SHPX), "Dev Commentary", + "Hey Folks, here's what is hopefully the last patch with major changes following v3.2, but it's a doozy!\n" + + "\n" + + "In addition to more mobile improvements, there's also a just recently finished overhaul to the title screen background!\n" + + "\n" + + "Note that both of the big new things in this update are likely to have a few quirks. If something seems out of place please let me know! I do expect to do one or two more patches after v3.2.4 to fix any minor issues that crop up.")); + + changes.addButton(new ChangeButton(Icons.get(Icons.DISPLAY_LAND), "New Title Screen Background!", + "**Shattered Pixel Dungeon has a new title screen background, with art by Aleksandar Komitov!**\n" + + "\n" + + "This new background is meant to both extend the classis archs, and tie the title screens more directly to the region splash arts! It features randomly selected floating fully rendered chunks of dungeon in front of an arch back-layer.\n" + + "\n" + + "Currently the background most strongly ties into the sewers region, but we have plans to add more variants in the future, one for each dungeon region!")); + + changes.addButton(new ChangeButton(Icons.get(Icons.DISPLAY_PORT), "Mobile Layout Changes", + "**Shattered now renders in true fullscreen on most mobile devices!**\n" + + "\n" + + "The status bar at the top of the in-game UI has been modified to work around small and medium sized hole punches and rounded corners on modern displays! This includes the dynamic island on modern iPhones. Thanks to these adjustments it's now possible for the UI to move up and for the game to display in true fullscreen during gameplay! Devices with larger cutouts like full-sized notches will unfortunately still have a dark bar on the top, as there isn't room for the UI.\n" + + "\n" + + "This also comes with a few other benefits for all mobile players. The XP bar has been moved and is now much more visible, and the hero buff bar now supports two rows, rather than compressing as heavily when there are many buffs at once.")); + changes = new ChangeInfo("v3.2.3", false, null); changes.hardlight(Window.TITLE_COLOR); changeInfos.add(changes); From 6a3d452aa0e5a49469d0d80e425631caa73653e5 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sat, 13 Sep 2025 13:18:07 -0400 Subject: [PATCH 13/62] v3.2.4: fixed far cluster layer in title screen not resetting --- .../shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java index 7803e0515..73f1fb9ce 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/TitleBackground.java @@ -80,6 +80,7 @@ public class TitleBackground extends Component { public static void reset(){ archs = null; clusters = null; + clustersFar = null; smallFars = null; mids1 = null; mids2 = null; From 399da145f308ffec24827ebb14f282dcbb0ceb3c Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 14 Sep 2025 10:19:43 -0400 Subject: [PATCH 14/62] v3.2.4: updated iPhone devices now that version info is out --- .../shatteredpixeldungeon/ios/IOSLauncher.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSLauncher.java b/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSLauncher.java index f19f02900..9caddae98 100644 --- a/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSLauncher.java +++ b/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSLauncher.java @@ -126,15 +126,14 @@ public class IOSLauncher extends IOSApplication.Delegate { config.addIosDevice("IPHONE_15_PRO", "iPhone16,1", 460); config.addIosDevice("IPHONE_15_PRO_MAX", "iPhone16,2", 460); config.addIosDevice("IPHONE_16_PRO", "iPhone17,1", 460); - config.addIosDevice("IPHONE_16_PRO_MAX", "iPhone17,2", 458); + config.addIosDevice("IPHONE_16_PRO_MAX", "iPhone17,2", 460); config.addIosDevice("IPHONE_16", "iPhone17,3", 460); config.addIosDevice("IPHONE_16_PLUS", "iPhone17,4", 460); config.addIosDevice("IPHONE_16E", "iPhone17,5", 460); - //TODO these four are guesses, machine strings may be incorrect, PPIs are correct or almost-correct though config.addIosDevice("IPHONE_17_PRO", "iPhone18,1", 460); config.addIosDevice("IPHONE_17_PRO_MAX", "iPhone18,2", 460); - config.addIosDevice("IPHONE_AIR", "iPhone18,3", 460); - config.addIosDevice("IPHONE_17", "iPhone18,4", 460); + config.addIosDevice("IPHONE_17", "iPhone18,3", 460); + config.addIosDevice("IPHONE_AIR", "iPhone18,4", 460); config.addIosDevice("IPAD_7G_WIFI", "iPad7,11", 264); config.addIosDevice("IPAD_7G_WIFI_CELLULAR", "iPad7,12", 264); @@ -181,6 +180,11 @@ public class IOSLauncher extends IOSApplication.Delegate { config.addIosDevice("IPAD_PRO_12.9_7G", "iPad16,5", 264); config.addIosDevice("IPAD_PRO_12.9_7G", "iPad16,6", 264); + //also override simulator devices for better testing when simulating modern iPhones + config.addIosDevice("SIMULATOR_32", "i386", 460); + config.addIosDevice("SIMULATOR_64", "x86_64", 460); + config.addIosDevice("SIMULATOR_ARM64", "arm64", 460); + return new IOSApplication(new ShatteredPixelDungeon(new IOSPlatformSupport()), config); } From f83cd78243f1ef61a510cf95aeb7f60bd5dd85f4 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 14 Sep 2025 11:24:58 -0400 Subject: [PATCH 15/62] v3.2.4: (English only atm) changed fullscreen settings text on mobile --- .../main/assets/messages/windows/windows.properties | 4 ++-- .../shatteredpixeldungeon/SPDSettings.java | 2 +- .../shatteredpixeldungeon/windows/WndSettings.java | 11 ++++++++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/core/src/main/assets/messages/windows/windows.properties b/core/src/main/assets/messages/windows/windows.properties index a9d9d3502..225d261cc 100644 --- a/core/src/main/assets/messages/windows/windows.properties +++ b/core/src/main/assets/messages/windows/windows.properties @@ -285,8 +285,8 @@ windows.wndscorebreakdown.old_score_desc=Games started prior to v1.3 have fewer windows.wndsettings$displaytab.title=Display Settings windows.wndsettings$displaytab.fullscreen=Fullscreen -windows.wndsettings$displaytab.saver=Power Saver -windows.wndsettings$displaytab.saver_desc=Power Saver mode draws the game at a reduced size and scales it up to fit your screen.\n\nThis will make graphics less crisp and enlarge the UI slightly, but will also improve performance and battery life.\n\nYou may need to restart the game for changes to take effect. +windows.wndsettings$displaytab.hide_nav=Hide Navigation Bar +windows.wndsettings$displaytab.hide_gesture=Hide Gesture Bar windows.wndsettings$displaytab.okay=Okay windows.wndsettings$displaytab.cancel=Cancel windows.wndsettings$displaytab.landscape=Force landscape diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/SPDSettings.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/SPDSettings.java index 614af1a65..16f7221f2 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/SPDSettings.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/SPDSettings.java @@ -49,7 +49,7 @@ public class SPDSettings extends GameSettings { //Display - public static final String KEY_FULLSCREEN = "fullscreen"; + public static final String KEY_FULLSCREEN = "fullscreen"; //used to hide navbars on mobile public static final String KEY_LANDSCAPE = "force_landscape"; public static final String KEY_ZOOM = "zoom"; public static final String KEY_BRIGHTNESS = "brightness"; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndSettings.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndSettings.java index 22109af64..e5c2736d8 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndSettings.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndSettings.java @@ -236,7 +236,16 @@ public class WndSettings extends WndTabbed { sep1 = new ColorBlock(1, 1, 0xFF000000); add(sep1); - chkFullscreen = new CheckBox( Messages.get(this, "fullscreen") ) { + String fullscreenText = Messages.get(this, "fullscreen"); + //TODO English only for now, make sure to translate later + if (Messages.lang() == Languages.ENGLISH){ + if (DeviceCompat.isAndroid()){ + fullscreenText = Messages.get(this, "hide_navigation"); + } else if (DeviceCompat.isiOS()){ + fullscreenText = Messages.get(this, "hide_gesture"); + } + } + chkFullscreen = new CheckBox( fullscreenText ) { @Override protected void onClick() { super.onClick(); From 2c0f1263a72b7b7b04b21ca172112025c33b42b0 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 14 Sep 2025 11:58:11 -0400 Subject: [PATCH 16/62] v3.2.4: updates to improve handling of Android cutouts: - HP bar can now resize-reposition to prevent being cut off - menu pane can now move inward to prevent being cut off - increased buff bar cut off sensitivity - slightly increased 'large cutout' permissiveness --- .../android/AndroidPlatformSupport.java | 5 ++- .../main/assets/interfaces/status_pane.png | Bin 1061 -> 5284 bytes .../scenes/GameScene.java | 42 +++++++++++++++--- .../ui/DangerIndicator.java | 4 +- .../shatteredpixeldungeon/ui/MenuPane.java | 1 + .../shatteredpixeldungeon/ui/StatusPane.java | 35 ++++++++++++--- 6 files changed, 70 insertions(+), 17 deletions(-) diff --git a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java index 67c9e6964..f9cdc4ccb 100644 --- a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java +++ b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java @@ -121,9 +121,10 @@ public class AndroidPlatformSupport extends PlatformSupport { for (Rect r : cutout.getBoundingRects()){ //use abs as some cutouts can apparently be returned inverted int cutoutSize = Math.abs(r.height() * r.width()); - //display cutouts are considered large if they take up more than 0.605% of the screen + //display cutouts are considered large if they take up more than 0.667% of the screen //in reality we want less than about 0.5%, but some cutouts over-report their size - if (cutoutSize*165 >= screenSize){ + //Pixel devices especially =S + if (cutoutSize*150 >= screenSize){ largeCutout = true; } } diff --git a/core/src/main/assets/interfaces/status_pane.png b/core/src/main/assets/interfaces/status_pane.png index cbe1ff0000f7fed1175d9f999b01f5f6cf014921..b2f836b03d23e025acdfa5c1db8fbd44a5a6fa3a 100644 GIT binary patch literal 5284 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 C4yYIa delta 777 zcmV+k1NQu+DWwRIBL)ErP)t-svkMRl0e=l+PZ$6I00MMUPE-E?<+m_O0008VNkloD<=~Afp4Xg+nT-%VHwLliw zW(q#onFX95*TQi8o3Jm1c|z|54Z#REX$15<8V*4S6R90qO^q^uLI`V2?F5y^RDWI_ zFp@bT<7P=A%0IvIr~}-u2_ZjkEpez^RvvwTbvArt*{Nz>fCuyeqj12;axO7nfHuH5 z6FxEso`~828xF7rJOc-iB)}L#Ob*BaIUon*fK&nHfrJA}n>tjs;p1I{;RTsJKN;NA)G1LTrx zHjslefPG2x8nWi=d>fz~rwI@`nuck405F@T_zIw)V*yeKK#}Gv*rIEz!a4)sY>I&G ziZy0$39x4p1nhn%@D_|n#eHLqwMVQ}mdHd{XQ1VYO$O!|m^?!3GkucBD1UvTSMmg% zkMv8PqVj>B$uqRx(R|#3a~8hGPPISa%GCwpVxawj@C9PJ{ec7* zh>rGS?r1;v_!o!{rsX1hG(Aahf!OX3gv{Xh5CD#dMRw0Oxyi+ys%{^}6NMC>e-kSJ z%b2j=QZuG~jQ3kGnG<%qs@t=x$Cz)y146E*PkR=35J@3~6hfLoWOkhiA6b$NqITG< z*)yaWM8}7O9i%o00000NkvXX Hu0mjfdyh`d diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index e1e9865ab..401e2ee5b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -368,22 +368,39 @@ public class GameScene extends PixelScene { int uiSize = SPDSettings.interfaceSize(); - //Some more medium sized display cutouts can obstruct the buff bar, so we limit the length - // of the 1st row in some cases + //display cutouts can obstruct various UI elements, so we need to adjust for that sometimes + float menuBarMaxLeft = uiCamera.width-insets.right-MenuPane.WIDTH; + int hpBarMaxWidth = 50; //default max width float buffBarTopRowMaxWidth = 50; //default max width if (largeInsetTop != insets.top){ - //most notably iOS's Dynamic island, which must exist in this case + //iOS's Dynamic island badly obstructs the first buff bar row if (DeviceCompat.isiOS()){ //TODO bad to hardcode this atm, need to change this so platformsupport returns cutout dimensions buffBarTopRowMaxWidth = 15; } else if (DeviceCompat.isAndroid()) { - //some android hole punches can also be big too + //Android hole punches are of varying size and may obstruct the menu, HP bar, or buff bar RectF cutout = Game.platform.getDisplayCutout().scale(1f / defaultZoom); + //if the cutout is positioned to obstruct the menu bar + if (cutout.top < 20 + && cutout.left < menuBarMaxLeft + MenuPane.WIDTH + && cutout.right > menuBarMaxLeft) { + menuBarMaxLeft = Math.min(menuBarMaxLeft, cutout.left - MenuPane.WIDTH); + //make sure we have space to actually move it though + menuBarMaxLeft = Math.max(menuBarMaxLeft, PixelScene.MIN_WIDTH_P-MenuPane.WIDTH); + } + //if the cutout is positioned to obstruct the HP bar + if (cutout.left < 78 + && cutout.top < 4 + && cutout.right > 32) { + //subtract starting position, but add a bit back due to end of bar + hpBarMaxWidth = Math.round(cutout.left - 32 + 4); + hpBarMaxWidth = Math.max(hpBarMaxWidth, 21); //cannot go below 21 (30 effective) + } //if the cutout is positioned to obstruct the buff bar if (cutout.left < 80 && cutout.top < 10 && cutout.right > 32 - && cutout.bottom > 12) { + && cutout.bottom > 11) { buffBarTopRowMaxWidth = cutout.left - 32; //subtract starting position } } @@ -396,11 +413,24 @@ public class GameScene extends PixelScene { menu = new MenuPane(); menu.camera = uiCamera; - menu.setPos( uiCamera.width-MenuPane.WIDTH-insets.right, screentop); + menu.setPos( menuBarMaxLeft, screentop); add(menu); + float extraRight = uiCamera.width - (menuBarMaxLeft + MenuPane.WIDTH); + if (extraRight > 0){ + SkinnedBlock bar = new SkinnedBlock(extraRight, 20, TextureCache.createSolid(0x88000000)); + bar.x = uiCamera.width - extraRight; + bar.camera = uiCamera; + add(bar); + + PointerArea blocker = new PointerArea(uiCamera.width - extraRight, 0, extraRight, 20); + blocker.camera = uiCamera; + add(blocker); + } + status = new StatusPane( SPDSettings.interfaceSize() > 0 ); status.camera = uiCamera; + StatusPane.hpBarMaxWidth = hpBarMaxWidth; StatusPane.buffBarTopRowMaxWidth = buffBarTopRowMaxWidth; status.setRect(insets.left, uiSize > 0 ? uiCamera.height-39-insets.bottom : screentop, uiCamera.width - insets.left - insets.right, 0 ); add(status); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/DangerIndicator.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/DangerIndicator.java index f0440efbf..1b5b4bf86 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/DangerIndicator.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/DangerIndicator.java @@ -73,14 +73,14 @@ public class DangerIndicator extends Tag { protected void layout() { super.layout(); - icon.x = right() - 10; + icon.x = left() + 14; icon.y = y + (height - icon.height) / 2; placeNumber(); } private void placeNumber() { - number.x = right() - 11 - number.width(); + number.x = left() + 13 - number.width(); number.y = y + (height - number.baseLine()) / 2f; PixelScene.align(number); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java index 01c3b87d4..c0c9a5343 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java @@ -208,6 +208,7 @@ public class MenuPane extends Component { } danger.setPos( x + WIDTH - danger.width(), y + bg.height + 1 ); + danger.setSize( camera.width - danger.width(), danger.height()); } public void pickup(Item item, int cell) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java index 05778f7dd..0dea1410a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java @@ -78,8 +78,10 @@ public class StatusPane extends Component { private boolean large; - //lower the buff indicator to avoid larger cutouts (e.g. iPhone dynamic island) - public static float cutoutOffset; + //potentially shrinks and/or repositions the hp bar to avoid some cutouts + public static int hpBarMaxWidth = 50; + private Image hpCutout; + //potentially cuts off the top row of the the buff indicator to avoid some cutouts public static float buffBarTopRowMaxWidth = 50; public StatusPane( boolean large ){ @@ -90,10 +92,13 @@ public class StatusPane extends Component { this.large = large; if (large) bg = new NinePatch( asset, 0, 64, 41, 39, 33, 0, 4, 0 ); - //right part is transparent now so Ninepatching doesn't actually do anything - else bg = new NinePatch( asset, 0, 0, 128, 38, 85, 0, 45, 0 ); + else bg = new NinePatch( asset, 0, 0, 82, 38, 32, 0, 5, 0 ); add( bg ); + hpCutout = new Image(asset, 90, 0, 12, 9); + hpCutout.visible = false; + add(hpCutout); + heroInfo = new Button(){ @Override protected void onClick () { @@ -179,7 +184,7 @@ public class StatusPane extends Component { bg.x = x; bg.y = y; if (large) bg.size( 160, bg.height ); //HP bars must be 128px wide atm - else bg.size( width, bg.height ); + else bg.size(hpBarMaxWidth+32, bg.height ); //default max right is 50px health bar + 32 avatar.x = bg.x - avatar.width / 2f + 15; avatar.y = bg.y - avatar.height / 2f + 16; @@ -216,7 +221,23 @@ public class StatusPane extends Component { exp.x = x+2; exp.y = y+30; - hp.x = shieldedHP.x = rawShielding.x = x + 30; + float hpleft = x + 30; + if (hpBarMaxWidth < 82){ + //the class variable assumes the left of the bar can't move, but we can inset it 9px + int hpWidth = (int)hpBarMaxWidth; + if (hpWidth <= 41){ + hpleft -= 9; + hpWidth += 9; + hpCutout.visible = true; + hpCutout.x = hpleft - 2; + hpCutout.y = y; + } + hp.frame(50-hpWidth, 40, 50, 4); + shieldedHP.frame(50-hpWidth, 44, 50, 4); + rawShielding.frame(50-hpWidth, 44, 50, 4); + } + + hp.x = shieldedHP.x = rawShielding.x = hpleft; hp.y = shieldedHP.y = rawShielding.y = y + 2; hpText.scale.set(PixelScene.align(0.5f)); @@ -234,7 +255,7 @@ public class StatusPane extends Component { heroInfoOnBar.setRect(heroInfo.right(), y, 50, 9); buffs.firstRowWidth = buffBarTopRowMaxWidth; - buffs.setRect( x + 31, y + 8 + cutoutOffset, 50, 15 ); + buffs.setRect( x + 31, y + 8, 50, 15 ); busy.x = x + 1; busy.y = y + 37; From 232f6b907d2d1d490afdc009a0fdebc16d06f6c6 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 14 Sep 2025 12:04:00 -0400 Subject: [PATCH 17/62] v3.2.4: softened the darkening fx on new background in welcome and about --- .../shatteredpixeldungeon/scenes/AboutScene.java | 2 +- .../shatteredpixeldungeon/scenes/WelcomeScene.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java index 49470e0b8..efb369118 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java @@ -56,7 +56,7 @@ public class AboutScene extends PixelScene { add( BG ); //darkens the arches - add(new ColorBlock(w, h, 0x88000000)); + add(new ColorBlock(w, h, 0x44000000)); ScrollPane list = new ScrollPane( new Component() ); add( list ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java index 569fd07c1..036eba8a7 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java @@ -81,10 +81,10 @@ public class WelcomeScene extends PixelScene { return; } - if (ShatteredPixelDungeon.versionCode == previousVersion && !SPDSettings.intro()) { + /*if (ShatteredPixelDungeon.versionCode == previousVersion && !SPDSettings.intro()) { ShatteredPixelDungeon.switchNoFade(TitleScene.class); return; - } + }*/ Music.INSTANCE.playTracks( new String[]{Assets.Music.THEME_1, Assets.Music.THEME_2}, @@ -101,7 +101,7 @@ public class WelcomeScene extends PixelScene { add( BG ); //darkens the arches - add(new ColorBlock(w, h, 0x88000000)); + add(new ColorBlock(w, h, 0x44000000)); w -= insets.left + insets.right; h -= insets.top + insets.bottom; From 557c527257b40cf1619f4ca919b0d2b658a3a1ef Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 14 Sep 2025 12:49:26 -0400 Subject: [PATCH 18/62] v3.2.4: buff bar dynamic island handling now varies by zoom --- .../shatteredpixeldungeon/scenes/GameScene.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index 401e2ee5b..0267ff88c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -375,8 +375,10 @@ public class GameScene extends PixelScene { if (largeInsetTop != insets.top){ //iOS's Dynamic island badly obstructs the first buff bar row if (DeviceCompat.isiOS()){ - //TODO bad to hardcode this atm, need to change this so platformsupport returns cutout dimensions - buffBarTopRowMaxWidth = 15; + //TODO bad to hardcode and approximate this atm + // need to change this so iOS platformsupport returns cutout dimensions + float cutoutLeft = (Game.width*0.3f)/defaultZoom; + buffBarTopRowMaxWidth = Math.min(50, cutoutLeft - 32); } else if (DeviceCompat.isAndroid()) { //Android hole punches are of varying size and may obstruct the menu, HP bar, or buff bar RectF cutout = Game.platform.getDisplayCutout().scale(1f / defaultZoom); From 947d2ef55d5210c85c8cfa370c3d573db0907ae4 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 14 Sep 2025 12:57:54 -0400 Subject: [PATCH 19/62] v3.2.4: fixed accidentally comitted welcome debug code --- .../shatteredpixeldungeon/scenes/WelcomeScene.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java index 036eba8a7..bff0bc387 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java @@ -81,10 +81,10 @@ public class WelcomeScene extends PixelScene { return; } - /*if (ShatteredPixelDungeon.versionCode == previousVersion && !SPDSettings.intro()) { + if (ShatteredPixelDungeon.versionCode == previousVersion && !SPDSettings.intro()) { ShatteredPixelDungeon.switchNoFade(TitleScene.class); return; - }*/ + } Music.INSTANCE.playTracks( new String[]{Assets.Music.THEME_1, Assets.Music.THEME_2}, From fdb10fc77914000af0907ac63f561ff21279115b Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 14 Sep 2025 13:07:24 -0400 Subject: [PATCH 20/62] v3.2.4: updated changelog and version for amended v3.2.4 release! --- build.gradle | 2 +- .../main/assets/messages/windows/windows.properties | 2 +- .../ui/changelist/v3_X_Changes.java | 10 ++++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 349da3a6c..40b94d1c6 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ allprojects { appName = 'Shattered Pixel Dungeon' appPackageName = 'com.shatteredpixel.shatteredpixeldungeon' - appVersionCode = 874 + appVersionCode = 875 appVersionName = '3.2.4' appJavaCompatibility = JavaVersion.VERSION_11 diff --git a/core/src/main/assets/messages/windows/windows.properties b/core/src/main/assets/messages/windows/windows.properties index 225d261cc..7d1def320 100644 --- a/core/src/main/assets/messages/windows/windows.properties +++ b/core/src/main/assets/messages/windows/windows.properties @@ -285,7 +285,7 @@ windows.wndscorebreakdown.old_score_desc=Games started prior to v1.3 have fewer windows.wndsettings$displaytab.title=Display Settings windows.wndsettings$displaytab.fullscreen=Fullscreen -windows.wndsettings$displaytab.hide_nav=Hide Navigation Bar +windows.wndsettings$displaytab.hide_navigation=Hide Navigation Bar windows.wndsettings$displaytab.hide_gesture=Hide Gesture Bar windows.wndsettings$displaytab.okay=Okay windows.wndsettings$displaytab.cancel=Cancel diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java index c801a4d3b..5623f989b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java @@ -111,6 +111,16 @@ public class v3_X_Changes { "\n" + "This also comes with a few other benefits for all mobile players. The XP bar has been moved and is now much more visible, and the hero buff bar now supports two rows, rather than compressing as heavily when there are many buffs at once.")); + changes.addButton(new ChangeButton(Icons.get(Icons.PREFS), "v3.2.4 Beta Tweaks", + "During v3.2.4's short beta I got a lot of good feedback about the new UI, and have made the following tweaks to address feedback before full release:\n" + + "\n" + + "**-** The HP bar can now shrink and/or reposition slightly if it would otherwise be cut off by a display cutout. The HP bar should shrink by about 20% at most.\n" + + "**-** Adjusted buff bar layout logic to reduce cases of top row getting slightly cut off by display cutouts on Android.\n" + + "**-** The menu pane on the right will now move to the left if there is room to do so and it would otherwise be cut off by a display cutout.\n" + + "**-** Slightly increased the permissiveness for what cutouts the game will try to render into. This should let the game render in true fullscreen on some devices with hole punches that it couldn't previously.\n" + + "**-** Improved how buff bar layout handles iOS dynamic island at smaller scale values.\n" + + "**-** Renamed the mobile fullscreen setting to 'hide navigation bar' or 'hide gesture bar'")); + changes = new ChangeInfo("v3.2.3", false, null); changes.hardlight(Window.TITLE_COLOR); changeInfos.add(changes); From 6daaa1febf3f4f536073d7e079e634ed21820c28 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Mon, 15 Sep 2025 11:08:08 -0400 Subject: [PATCH 21/62] v3.2.5: compressed recently changed status pane assets --- .../main/assets/interfaces/status_pane.png | Bin 5284 -> 1101 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/core/src/main/assets/interfaces/status_pane.png b/core/src/main/assets/interfaces/status_pane.png index b2f836b03d23e025acdfa5c1db8fbd44a5a6fa3a..6d30faf732656961cd93bcad1bd245ba59f35cd5 100644 GIT binary patch delta 818 zcmV-21I_%TDa{CwBL)ErP)t-svkMRl0e=l+PZ$6I00MMUPE-E?<+m_O0008-NklVRXE~R(9suuRg10rfKEODG#uno^@%RYBU<`Mr{pp1e4tzMgjU|uF?mW`@92^| zqoucWN}kis8@eSgXyr8>lb2laim05hSt%g>8m530kOERb3Xld@18J~7V5*9M8te}c zR)hTkf@-io5LSczfuI`f4}XN!V1FR22Kxiy#Xr9P&-MpWKnh3!TLm7-MglIa^0!IM z0KqX=32Y*O?c2Ugd+Rr+vwo(R#DRkQ*e(Je){-pp$Cyt$7vA7 z7(~dQcIeOwKo|(3;N8ARpe72yVCXR-CaqoYDdU@+66Qu_JTUz*9WZ&o12a*x#R}F7 w(}L-Q$pao3i5e{`SRWru1=9tS2YR9U23Y3I^-NrI;{X5v07*qoM6N<$f@zg(c>n+a literal 5284 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 C4yYIa From e4a334412d65d65c3ea9839551e6e9b80791e8a0 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Wed, 17 Sep 2025 17:02:54 -0400 Subject: [PATCH 22/62] v3.2.5: more Android display cutout stuff: - added proper support for top-left cutouts, hero pane can extend a bit - made Android 'smaller cutout' detection more permissive again - added a check to not trust devices with no reported cutout --- .../android/AndroidPlatformSupport.java | 24 +++++++++++---- .../scenes/GameScene.java | 18 ++++++++--- .../shatteredpixeldungeon/ui/StatusPane.java | 30 +++++++++++++++---- 3 files changed, 56 insertions(+), 16 deletions(-) diff --git a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java index f9cdc4ccb..da6399ea6 100644 --- a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java +++ b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidPlatformSupport.java @@ -117,17 +117,29 @@ public class AndroidPlatformSupport extends PlatformSupport { if (cutout != null) { boolean largeCutout = false; + boolean cutoutsPresent = false; + int screenSize = Game.width * Game.height; - for (Rect r : cutout.getBoundingRects()){ + for (Rect r : cutout.getBoundingRects()) { //use abs as some cutouts can apparently be returned inverted int cutoutSize = Math.abs(r.height() * r.width()); - //display cutouts are considered large if they take up more than 0.667% of the screen - //in reality we want less than about 0.5%, but some cutouts over-report their size - //Pixel devices especially =S - if (cutoutSize*150 >= screenSize){ - largeCutout = true; + //display cutouts are considered large if they take up more than 0.75% + // of the screen/ in reality we want less than about 0.5%, + // but some cutouts over-report their size, Pixel devices especially =S + if (cutoutSize > 0){ + cutoutsPresent = true; + if (cutoutSize * 133.33f >= screenSize) { + largeCutout = true; + } } } + + if (!cutoutsPresent){ + //if we get no cutouts reported, assume the device is lying to us + // and there actually is a cutout, which we must assume is large =S + largeCutout = true; + } + if (largeCutout || level == INSET_ALL) { insets.left = Math.max(insets.left, cutout.getSafeInsetLeft()); insets.top = Math.max(insets.top, cutout.getSafeInsetTop()); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index 0267ff88c..9f8363718 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -369,10 +369,11 @@ public class GameScene extends PixelScene { int uiSize = SPDSettings.interfaceSize(); //display cutouts can obstruct various UI elements, so we need to adjust for that sometimes + float heroPaneExtraWidth = insets.left; float menuBarMaxLeft = uiCamera.width-insets.right-MenuPane.WIDTH; int hpBarMaxWidth = 50; //default max width float buffBarTopRowMaxWidth = 50; //default max width - if (largeInsetTop != insets.top){ + if (largeInsetTop == 0){ //iOS's Dynamic island badly obstructs the first buff bar row if (DeviceCompat.isiOS()){ //TODO bad to hardcode and approximate this atm @@ -380,10 +381,18 @@ public class GameScene extends PixelScene { float cutoutLeft = (Game.width*0.3f)/defaultZoom; buffBarTopRowMaxWidth = Math.min(50, cutoutLeft - 32); } else if (DeviceCompat.isAndroid()) { - //Android hole punches are of varying size and may obstruct the menu, HP bar, or buff bar + //Android hole punches are of varying size and may obstruct various UI elements RectF cutout = Game.platform.getDisplayCutout().scale(1f / defaultZoom); + //if the cutout is positioned to obstruct the hero portrait in the status pane + if (cutout.top < 30 + && cutout.left < 20 + && cutout.right > 12) { + heroPaneExtraWidth = Math.max(heroPaneExtraWidth, cutout.right-12); + //make sure we have space to actually move it though + heroPaneExtraWidth = Math.min(heroPaneExtraWidth, uiCamera.width - PixelScene.MIN_WIDTH_P); + } //if the cutout is positioned to obstruct the menu bar - if (cutout.top < 20 + else if (cutout.top < 20 && cutout.left < menuBarMaxLeft + MenuPane.WIDTH && cutout.right > menuBarMaxLeft) { menuBarMaxLeft = Math.min(menuBarMaxLeft, cutout.left - MenuPane.WIDTH); @@ -391,7 +400,7 @@ public class GameScene extends PixelScene { menuBarMaxLeft = Math.max(menuBarMaxLeft, PixelScene.MIN_WIDTH_P-MenuPane.WIDTH); } //if the cutout is positioned to obstruct the HP bar - if (cutout.left < 78 + else if (cutout.left < 78 && cutout.top < 4 && cutout.right > 32) { //subtract starting position, but add a bit back due to end of bar @@ -432,6 +441,7 @@ public class GameScene extends PixelScene { status = new StatusPane( SPDSettings.interfaceSize() > 0 ); status.camera = uiCamera; + StatusPane.heroPaneExtraWidth = heroPaneExtraWidth; StatusPane.hpBarMaxWidth = hpBarMaxWidth; StatusPane.buffBarTopRowMaxWidth = buffBarTopRowMaxWidth; status.setRect(insets.left, uiSize > 0 ? uiCamera.height-39-insets.bottom : screentop, uiCamera.width - insets.left - insets.right, 0 ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java index 0dea1410a..ac226cde8 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java @@ -78,6 +78,9 @@ public class StatusPane extends Component { private boolean large; + //potentially extends the hero portrait space to avoid some cutouts + public static float heroPaneExtraWidth = 0; + private NinePatch heroPaneCutout; //potentially shrinks and/or repositions the hp bar to avoid some cutouts public static int hpBarMaxWidth = 50; private Image hpCutout; @@ -95,6 +98,10 @@ public class StatusPane extends Component { else bg = new NinePatch( asset, 0, 0, 82, 38, 32, 0, 5, 0 ); add( bg ); + heroPaneCutout = new NinePatch(asset, 0, 0, 5, 36, 4, 0, 0, 0); + heroPaneCutout.visible = false; + add(heroPaneCutout); + hpCutout = new Image(asset, 90, 0, 12, 9); hpCutout.visible = false; add(hpCutout); @@ -181,7 +188,9 @@ public class StatusPane extends Component { height = large ? 39 : 38; - bg.x = x; + float heroPaneWidth = 30 + heroPaneExtraWidth; + + bg.x = x + heroPaneExtraWidth; bg.y = y; if (large) bg.size( 160, bg.height ); //HP bars must be 128px wide atm else bg.size(hpBarMaxWidth+32, bg.height ); //default max right is 50px health bar + 32 @@ -190,7 +199,7 @@ public class StatusPane extends Component { avatar.y = bg.y - avatar.height / 2f + 16; PixelScene.align(avatar); - heroInfo.setRect( x, y, 30, large ? 40 : 36 ); + heroInfo.setRect( x, y, heroPaneWidth, large ? 40 : 36 ); compass.x = avatar.x + avatar.width / 2f - compass.origin.x; compass.y = avatar.y + avatar.height / 2f - compass.origin.y; @@ -221,7 +230,14 @@ public class StatusPane extends Component { exp.x = x+2; exp.y = y+30; - float hpleft = x + 30; + if (heroPaneExtraWidth > 0){ + heroPaneCutout.visible = true; + heroPaneCutout.x = x; + heroPaneCutout.y = y; + heroPaneCutout.size(heroPaneExtraWidth+4, heroPaneCutout.height); + } + + float hpleft = x + heroPaneWidth; if (hpBarMaxWidth < 82){ //the class variable assumes the left of the bar can't move, but we can inset it 9px int hpWidth = (int)hpBarMaxWidth; @@ -255,7 +271,7 @@ public class StatusPane extends Component { heroInfoOnBar.setRect(heroInfo.right(), y, 50, 9); buffs.firstRowWidth = buffBarTopRowMaxWidth; - buffs.setRect( x + 31, y + 8, 50, 15 ); + buffs.setRect( x + heroPaneWidth + 1, y + 8, 50, 15 ); busy.x = x + 1; busy.y = y + 37; @@ -322,7 +338,7 @@ public class StatusPane extends Component { expText.x = hp.x + (128 - expText.width())/2f; } else { - exp.scale.x = (17 / exp.width) * Dungeon.hero.exp / Dungeon.hero.maxExp(); + exp.scale.x = ((17 + heroPaneExtraWidth) / exp.width) * Dungeon.hero.exp / Dungeon.hero.maxExp(); expText.text(Dungeon.hero.exp + "/" + Dungeon.hero.maxExp()); } @@ -342,7 +358,7 @@ public class StatusPane extends Component { } else { level.text( Integer.toString( lastLvl ) ); level.measure(); - level.x = x + 25.5f - level.width() / 2f; + level.x = x + heroPaneExtraWidth + 25.5f - level.width() / 2f; level.y = y + 31.0f - level.baseLine() / 2f; } PixelScene.align(level); @@ -364,6 +380,8 @@ public class StatusPane extends Component { public void alpha( float value ){ value = GameMath.gate(0, value, 1f); bg.alpha(value); + heroPaneCutout.alpha(value); + hpCutout.alpha(value); avatar.alpha(value); rawShielding.alpha(0.5f*value); shieldedHP.alpha(value); From 98547cdf82c5fa64a4d08ca94e405bf086a7b81d Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 18 Sep 2025 11:07:18 -0400 Subject: [PATCH 23/62] v3.2.5: reverted some corner UI insets on desktop --- .../shatteredpixeldungeon/scenes/RankingsScene.java | 3 ++- .../shatteredpixeldungeon/scenes/TitleScene.java | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java index d6b730a1b..28c3198b5 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/RankingsScene.java @@ -47,6 +47,7 @@ import com.watabou.noosa.BitmapText; import com.watabou.noosa.Camera; import com.watabou.noosa.Image; import com.watabou.noosa.audio.Music; +import com.watabou.utils.DeviceCompat; import com.watabou.utils.GameMath; import com.watabou.utils.RectF; @@ -147,7 +148,7 @@ public class RankingsScene extends PixelScene { btnExit.setPos( Camera.main.width - btnExit.width() - insets.right, insets.top ); add( btnExit ); - float left = insets.left + (PixelScene.landscape() ? 10 : 0); + float left = insets.left + (PixelScene.landscape() && !DeviceCompat.isDesktop() ? 10 : 0); if (Rankings.INSTANCE.latestDaily != null) { IconButton btnDailies = new IconButton(Icons.CALENDAR.get()) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java index 80eb580dd..3b1b91069 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java @@ -221,9 +221,8 @@ public class TitleScene extends PixelScene { BitmapText version = new BitmapText( "v" + Game.version, pixelFont); version.measure(); version.hardlight( 0x888888 ); - //TODO perhaps extra check for Android top-right / top-left notches? - version.x = insets.left + w - version.width() - 8; - version.y = insets.top + h - version.height() - 4; + version.x = insets.left + w - version.width() - (DeviceCompat.isDesktop() ? 4 : 8); + version.y = insets.top + h - version.height() - (DeviceCompat.isDesktop() ? 2 : 4); add( version ); if (DeviceCompat.isDesktop()) { From 5fb32d6f0af4a23513179e9dcb8a48dd17f90480 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 18 Sep 2025 11:16:53 -0400 Subject: [PATCH 24/62] v3.2.5: radiance now checks if char was killed before applying paralysis --- .../shatteredpixeldungeon/actors/hero/spells/Radiance.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/Radiance.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/Radiance.java index 0f830071f..788d1298c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/Radiance.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/Radiance.java @@ -74,7 +74,9 @@ public class Radiance extends ClericSpell { Buff.affect(mob, GuidingLight.Illuminated.class); Buff.affect(mob, GuidingLight.WasIlluminatedTracker.class); } - Buff.affect(mob, Paralysis.class, 3f); + if (mob.isActive()) { + Buff.affect(mob, Paralysis.class, 3f); + } } } From 0a2984c11d87f95b46155e7cde453a3282300206 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 18 Sep 2025 11:58:09 -0400 Subject: [PATCH 25/62] v3.2.5: Updated missing native handling on Android --- .../shatteredpixeldungeon/android/AndroidLauncher.java | 3 ++- .../android/AndroidMissingNativesHandler.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidLauncher.java b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidLauncher.java index f73f0f4ec..8abaea06a 100644 --- a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidLauncher.java +++ b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidLauncher.java @@ -66,11 +66,12 @@ public class AndroidLauncher extends AndroidApplication { GdxNativesLoader.load(); FreeType.initFreeType(); } catch (Exception e){ + GdxNativesLoader.disableNativesLoading = true; AndroidMissingNativesHandler.error = e; Intent intent = new Intent(this, AndroidMissingNativesHandler.class); startActivity(intent); finish(); - return; + //let initialization continue for a moment so that we can set up things libGDX expects to be set up } //there are some things we only need to set up on first launch diff --git a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidMissingNativesHandler.java b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidMissingNativesHandler.java index 418fe8401..9c15bd50c 100644 --- a/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidMissingNativesHandler.java +++ b/android/src/main/java/com/shatteredpixel/shatteredpixeldungeon/android/AndroidMissingNativesHandler.java @@ -65,7 +65,7 @@ public class AndroidMissingNativesHandler extends Activity { } TextView text = new TextView(this); - String message = "ShatteredPD failed to access some of its internal code and cannot start!\n\n" + + String message = "Shattered Pixel Dungeon failed to access some of its internal code and cannot start!\n\n" + "Try downloading the game from an official source if you haven't already. You can also screenshot this debug info and send it to the developer (Evan@ShatteredPixel.com):"; message += "\n\nPackage: " + getPackageName(); @@ -88,7 +88,7 @@ public class AndroidMissingNativesHandler extends Activity { text.setTextColor(0xFFFFFFFF); text.setTypeface(Typeface.createFromAsset(getAssets(), "fonts/pixel_font.ttf")); text.setGravity(Gravity.CENTER_VERTICAL); - text.setPadding(10, 10, 10, 10); + text.setPadding(20, 20, 20, 20); setContentView(text); } From 29027d7ac2ecba384bacb384eb5dc32c825c5a88 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 18 Sep 2025 12:12:38 -0400 Subject: [PATCH 26/62] v3.2.5: fixed guard chaining allies not updating their sprite visibility --- .../shatteredpixel/shatteredpixeldungeon/actors/mobs/Guard.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Guard.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Guard.java index 76265d9aa..b0cf6cbc7 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Guard.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Guard.java @@ -127,6 +127,8 @@ public class Guard extends Mob { Dungeon.hero.interrupt(); Dungeon.observe(); GameScene.updateFog(); + } else { + enemy.sprite.visible = Dungeon.level.heroFOV[pullPos]; } } From 389fbc45e7fdddb5cf8cfc02870b6929b003d26b Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 18 Sep 2025 12:14:02 -0400 Subject: [PATCH 27/62] v3.2.5: levelling up dried rose while ghost is summoned now heals it --- .../shatteredpixeldungeon/items/artifacts/DriedRose.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java index bf0d5e7ed..62356be01 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java @@ -345,6 +345,7 @@ public class DriedRose extends Artifact { if (ghost != null){ ghost.updateRose(); + ghost.HP = Math.min(ghost.HP+8, ghost.HT); } return super.upgrade(); From 1dedfb30291fab3e4ebfda75b2db62c9003d6861 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 18 Sep 2025 12:22:39 -0400 Subject: [PATCH 28/62] v3.2.5: fixed tab cycling in WndBag --- .../shatteredpixel/shatteredpixeldungeon/windows/WndBag.java | 3 +++ .../shatteredpixeldungeon/windows/WndTabbed.java | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndBag.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndBag.java index 6d2b0c581..8dd0b8e41 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndBag.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndBag.java @@ -133,6 +133,9 @@ public class WndBag extends WndTabbed { BagTab tab = new BagTab( b, i++ ); add( tab ); tab.select( b == bag ); + if (b == bag){ + selected = tab; + } } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndTabbed.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndTabbed.java index 5a9f18357..390fc8fc6 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndTabbed.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndTabbed.java @@ -57,7 +57,7 @@ public class WndTabbed extends Window { int idx = tabs.indexOf(selected); idx++; if (idx >= tabs.size()) idx = 0; - select(idx); + tabs.get(idx).onClick(); return true; } From 7d2098426b88b66110d80ba9a53876ce683b729c Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 18 Sep 2025 12:36:26 -0400 Subject: [PATCH 29/62] v3.2.5: added some sync checks to sprite addition and removed old adds --- .../scenes/GameScene.java | 26 +++---------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index 9f8363718..201963180 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -1003,29 +1003,21 @@ public class GameScene extends PixelScene { customWalls.add( visual.create() ); } - private void addHeapSprite( Heap heap ) { + private synchronized void addHeapSprite( Heap heap ) { ItemSprite sprite = heap.sprite = (ItemSprite)heaps.recycle( ItemSprite.class ); sprite.revive(); sprite.link( heap ); heaps.add( sprite ); } - private void addDiscardedSprite( Heap heap ) { + private synchronized void addDiscardedSprite( Heap heap ) { heap.sprite = (DiscardedItemSprite)heaps.recycle( DiscardedItemSprite.class ); heap.sprite.revive(); heap.sprite.link( heap ); heaps.add( heap.sprite ); } - private void addPlantSprite( Plant plant ) { - - } - - private void addTrapSprite( Trap trap ) { - - } - - private void addBlobSprite( final Blob gas ) { + private synchronized void addBlobSprite( final Blob gas ) { if (gas.emitter == null) { gases.add( new BlobEmitter( gas ) ); } @@ -1100,18 +1092,6 @@ public class GameScene extends PixelScene { } // ------------------------------------------------------- - - public static void add( Plant plant ) { - if (scene != null) { - scene.addPlantSprite( plant ); - } - } - - public static void add( Trap trap ) { - if (scene != null) { - scene.addTrapSprite( trap ); - } - } public static void add( Blob gas ) { Actor.add( gas ); From efb58becba50f20e55c470ca3778e15be18db58e Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 18 Sep 2025 12:59:40 -0400 Subject: [PATCH 30/62] v3.2.5: added functionality for item variable pickup delay --- .../shatteredpixeldungeon/items/Dewdrop.java | 2 +- .../items/EnergyCrystal.java | 2 +- .../shatteredpixeldungeon/items/Gold.java | 2 +- .../shatteredpixeldungeon/items/Item.java | 6 +++++- .../items/LostBackpack.java | 2 +- .../items/artifacts/DriedRose.java | 4 ++-- .../items/artifacts/MasterThievesArmband.java | 2 +- .../items/artifacts/TimekeepersHourglass.java | 2 +- .../items/journal/DocumentPage.java | 2 +- .../items/journal/Guidebook.java | 2 +- .../shatteredpixeldungeon/items/keys/Key.java | 2 +- .../items/spells/TelekineticGrab.java | 4 ++-- .../items/weapon/missiles/HeavyBoomerang.java | 19 +++++++++++-------- .../items/weapon/missiles/MissileWeapon.java | 2 +- .../items/weapon/missiles/ThrowingClub.java | 9 ++------- .../items/weapon/missiles/ThrowingHammer.java | 9 ++------- 16 files changed, 34 insertions(+), 37 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Dewdrop.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Dewdrop.java index 9322ae946..3d7af0a80 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Dewdrop.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Dewdrop.java @@ -74,7 +74,7 @@ public class Dewdrop extends Item { } Sample.INSTANCE.play( Assets.Sounds.DEWDROP ); - hero.spendAndNext( TIME_TO_PICK_UP ); + hero.spendAndNext( pickupDelay() ); return true; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/EnergyCrystal.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/EnergyCrystal.java index 158e3c1b3..ed4964374 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/EnergyCrystal.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/EnergyCrystal.java @@ -64,7 +64,7 @@ public class EnergyCrystal extends Item { GameScene.pickUp( this, pos ); hero.sprite.showStatusWithIcon( 0x44CCFF, Integer.toString(quantity), FloatingText.ENERGY ); - hero.spendAndNext( TIME_TO_PICK_UP ); + hero.spendAndNext( pickupDelay() ); Sample.INSTANCE.play( Assets.Sounds.ITEM ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Gold.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Gold.java index 6994ae0eb..4610a6d05 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Gold.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Gold.java @@ -68,7 +68,7 @@ public class Gold extends Item { GameScene.pickUp( this, pos ); hero.sprite.showStatusWithIcon( CharSprite.NEUTRAL, Integer.toString(quantity), FloatingText.GOLD ); - hero.spendAndNext( TIME_TO_PICK_UP ); + hero.spendAndNext( pickupDelay() ); Sample.INSTANCE.play( Assets.Sounds.GOLD, 1, 1, Random.Float( 0.9f, 1.1f ) ); updateQuickslot(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Item.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Item.java index 10bfacf7b..ddbac4a7a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Item.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/Item.java @@ -126,7 +126,7 @@ public class Item implements Bundlable { GameScene.pickUp( this, pos ); Sample.INSTANCE.play( Assets.Sounds.ITEM ); - hero.spendAndNext( TIME_TO_PICK_UP ); + hero.spendAndNext( pickupDelay() ); return true; } else { @@ -697,6 +697,10 @@ public class Item implements Bundlable { public float castDelay( Char user, int cell ){ return TIME_TO_THROW; } + + public float pickupDelay(){ + return TIME_TO_PICK_UP; + } protected static Hero curUser = null; protected static Item curItem = null; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/LostBackpack.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/LostBackpack.java index 0431fbffa..4a61836db 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/LostBackpack.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/LostBackpack.java @@ -77,7 +77,7 @@ public class LostBackpack extends Item { Item.updateQuickslot(); Sample.INSTANCE.play( Assets.Sounds.DEWDROP ); - hero.spendAndNext(TIME_TO_PICK_UP); + hero.spendAndNext(pickupDelay()); GameScene.pickUp( this, pos ); ((HeroSprite)hero.sprite).updateArmor(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java index 62356be01..24fe5d28d 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/DriedRose.java @@ -503,7 +503,7 @@ public class DriedRose extends Artifact { return false; } if ( rose.level() >= rose.levelCap ){ GLog.i( Messages.get(this, "no_room") ); - hero.spendAndNext(TIME_TO_PICK_UP); + hero.spendAndNext(pickupDelay()); return true; } else { @@ -516,7 +516,7 @@ public class DriedRose extends Artifact { Sample.INSTANCE.play( Assets.Sounds.DEWDROP ); GameScene.pickUp(this, pos); - hero.spendAndNext(TIME_TO_PICK_UP); + hero.spendAndNext(pickupDelay()); return true; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/MasterThievesArmband.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/MasterThievesArmband.java index 3d860237e..68aeb512e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/MasterThievesArmband.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/MasterThievesArmband.java @@ -165,7 +165,7 @@ public class MasterThievesArmband extends Artifact { } else { if (loot.doPickUp(curUser)) { //item collection happens instantly - curUser.spend(-TIME_TO_PICK_UP); + curUser.spend(-loot.pickupDelay()); } else { Dungeon.level.drop(loot, curUser.pos).sprite.drop(); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/TimekeepersHourglass.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/TimekeepersHourglass.java index 3a2c11f5c..ea16b2a94 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/TimekeepersHourglass.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/TimekeepersHourglass.java @@ -518,7 +518,7 @@ public class TimekeepersHourglass extends Artifact { else GLog.i( Messages.get(this, "levelup") ); GameScene.pickUp(this, pos); - hero.spendAndNext(TIME_TO_PICK_UP); + hero.spendAndNext(pickupDelay()); return true; } else { GLog.w( Messages.get(this, "no_hourglass") ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/journal/DocumentPage.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/journal/DocumentPage.java index 3d1a2f8a6..ef79e4a8f 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/journal/DocumentPage.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/journal/DocumentPage.java @@ -64,7 +64,7 @@ public abstract class DocumentPage extends Item { } document().findPage(page); Sample.INSTANCE.play( Assets.Sounds.ITEM ); - hero.spendAndNext( TIME_TO_PICK_UP ); + hero.spendAndNext( pickupDelay() ); return true; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/journal/Guidebook.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/journal/Guidebook.java index af1b391b1..ab49ebc05 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/journal/Guidebook.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/journal/Guidebook.java @@ -63,7 +63,7 @@ public class Guidebook extends Item { } GameScene.flashForDocument(Document.ADVENTURERS_GUIDE, Document.GUIDE_INTRO); Sample.INSTANCE.play( Assets.Sounds.ITEM ); - hero.spendAndNext( TIME_TO_PICK_UP ); + hero.spendAndNext( pickupDelay() ); return true; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/keys/Key.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/keys/Key.java index e5b517499..a0beab19c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/keys/Key.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/keys/Key.java @@ -57,7 +57,7 @@ public abstract class Key extends Item { WndJournal.last_index = 0; Notes.add(this); Sample.INSTANCE.play( Assets.Sounds.ITEM ); - hero.spendAndNext( TIME_TO_PICK_UP ); + hero.spendAndNext( pickupDelay() ); GameScene.updateKeyDisplay(); return true; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/TelekineticGrab.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/TelekineticGrab.java index 6cd4331cc..3e6a8e98a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/TelekineticGrab.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/TelekineticGrab.java @@ -75,7 +75,7 @@ public class TelekineticGrab extends TargetedSpell { Item item = ch.buff(PinCushion.class).grabOne(); if (item.doPickUp(hero, ch.pos)) { - hero.spend(-Item.TIME_TO_PICK_UP); //casting the spell already takes a turn + hero.spend(-item.pickupDelay()); //casting the spell already takes a turn GLog.i( Messages.capitalize(Messages.get(hero, "you_now_have", item.name())) ); } else { @@ -100,7 +100,7 @@ public class TelekineticGrab extends TargetedSpell { Item item = h.peek(); if (item.doPickUp(hero, h.pos)) { h.pickUp(); - hero.spend(-Item.TIME_TO_PICK_UP); //casting the spell already takes a turn + hero.spend(-item.pickupDelay()); //casting the spell already takes a turn GLog.i( Messages.capitalize(Messages.get(hero, "you_now_have", item.name())) ); } else { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/HeavyBoomerang.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/HeavyBoomerang.java index 93f0a0073..c30bd0caf 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/HeavyBoomerang.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/HeavyBoomerang.java @@ -51,16 +51,22 @@ public class HeavyBoomerang extends MissileWeapon { (tier-1) * lvl; //3 scaling, down from 4 } - boolean circleBackhit = false; + boolean circlingBack = false; @Override protected float adjacentAccFactor(Char owner, Char target) { - if (circleBackhit){ + if (circlingBack){ return 1.5f; } return super.adjacentAccFactor(owner, target); } + @Override + public float pickupDelay() { + //pickup is instant when circling back + return circlingBack ? 0f : super.pickupDelay(); + } + @Override protected void rangedHit(Char enemy, int cell) { decrementDurability(); @@ -126,22 +132,18 @@ public class HeavyBoomerang extends MissileWeapon { @Override public void call() { detach(); + boomerang.circlingBack = true; if (returnTarget == target){ if (!boomerang.spawnedForEffect) { - if (target instanceof Hero && boomerang.doPickUp((Hero) target)) { - //grabbing the boomerang takes no time - ((Hero) target).spend(-TIME_TO_PICK_UP); - } else { + if (!(target instanceof Hero) || !boomerang.doPickUp((Hero) target)) { Dungeon.level.drop(boomerang, returnPos).sprite.drop(); } } } else if (returnTarget != null){ - boomerang.circleBackhit = true; if (((Hero)target).shoot( returnTarget, boomerang )) { boomerang.decrementDurability(); } - boomerang.circleBackhit = false; if (!boomerang.spawnedForEffect && boomerang.durability > 0) { Dungeon.level.drop(boomerang, returnPos).sprite.drop(); } @@ -149,6 +151,7 @@ public class HeavyBoomerang extends MissileWeapon { } else if (!boomerang.spawnedForEffect) { Dungeon.level.drop(boomerang, returnPos).sprite.drop(); } + boomerang.circlingBack = false; CircleBack.this.next(); } }); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java index b287e1fd5..562e93c74 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java @@ -598,7 +598,7 @@ abstract public class MissileWeapon extends Weapon { parent = null; if (!UpgradedSetTracker.pickupValid(hero, this)){ Sample.INSTANCE.play( Assets.Sounds.ITEM ); - hero.spendAndNext( TIME_TO_PICK_UP ); + hero.spendAndNext( pickupDelay() ); GLog.w(Messages.get(this, "dust")); quantity(0); return true; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/ThrowingClub.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/ThrowingClub.java index cdb3308dd..f96675926 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/ThrowingClub.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/ThrowingClub.java @@ -22,7 +22,6 @@ package com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles; import com.shatteredpixel.shatteredpixeldungeon.Assets; -import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; public class ThrowingClub extends MissileWeapon { @@ -38,12 +37,8 @@ public class ThrowingClub extends MissileWeapon { } @Override - public boolean doPickUp(Hero hero, int pos) { - if (super.doPickUp(hero, pos)){ - hero.spendAndNext( -hero.cooldown() ); - return true; - } - return false; + public float pickupDelay() { + return 0; //picked up instantly } @Override diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/ThrowingHammer.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/ThrowingHammer.java index 2963bf571..d0f65c688 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/ThrowingHammer.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/ThrowingHammer.java @@ -22,7 +22,6 @@ package com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles; import com.shatteredpixel.shatteredpixeldungeon.Assets; -import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; public class ThrowingHammer extends MissileWeapon { @@ -38,12 +37,8 @@ public class ThrowingHammer extends MissileWeapon { } @Override - public boolean doPickUp(Hero hero, int pos) { - if (super.doPickUp(hero, pos)){ - hero.spendAndNext( -hero.cooldown() ); - return true; - } - return false; + public float pickupDelay() { + return 0; //picked up instantly } @Override From c471924d583d2a8d6245fd6f2f2e8635d27753f1 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 18 Sep 2025 13:19:59 -0400 Subject: [PATCH 31/62] v3.2.5: fixed guards pulling large chargs into enclosed spaces --- .../shatteredpixeldungeon/actors/mobs/Guard.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Guard.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Guard.java index b0cf6cbc7..7588000ad 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Guard.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Guard.java @@ -80,7 +80,9 @@ public class Guard extends Mob { else { int newPos = -1; for (int i : chain.subPath(1, chain.dist)){ - if (!Dungeon.level.solid[i] && Actor.findChar(i) == null){ + //find the closest position to the guard that's open for the target + if (!Dungeon.level.solid[i] && Actor.findChar(i) == null + && (Dungeon.level.openSpace[i] || !Char.hasProp(enemy, Property.LARGE))){ newPos = i; break; } From d7ab66058b6ae89c4561d3d9397a5a6efd26d60e Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 18 Sep 2025 13:23:32 -0400 Subject: [PATCH 32/62] v3.2.5: fixed rats made neutral due to ratmog attacking the hero --- .../shatteredpixel/shatteredpixeldungeon/actors/mobs/Rat.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Rat.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Rat.java index 8be6726e7..629f917f7 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Rat.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Rat.java @@ -41,10 +41,11 @@ public class Rat extends Mob { @Override protected boolean act() { - if (alignment == Alignment.ENEMY + if (alignment != Alignment.ALLY && Dungeon.level.heroFOV[pos] && Dungeon.hero.armorAbility instanceof Ratmogrify){ alignment = Alignment.NEUTRAL; + if (enemy == Dungeon.hero) enemy = null; if (state == SLEEPING) state = WANDERING; } return super.act(); From 7d10b6051ae6dfdfa86b1040471c9f57c80c601f Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 18 Sep 2025 13:33:18 -0400 Subject: [PATCH 33/62] v3.2.5: adjusted custom mouse cursor asset to be square --- core/src/main/assets/gdx/cursor_mouse.png | Bin 123 -> 127 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/core/src/main/assets/gdx/cursor_mouse.png b/core/src/main/assets/gdx/cursor_mouse.png index 2a87bf5d3bb8b95ab4cebab70eb883820e31c7b4..9e052ca9a29afc9df9b8f311987d14f0cb233fda 100644 GIT binary patch literal 127 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Zk{fVAr*|t3{A!bK57=5i$4GP zKSiP_?a`UO{|-Le6w`$+FaFOQ>)58q!F*uW$pX$p3@YIbhL&sxa@CHrPC3dX(;s5M a#ZbE3dF$$*`+fjTWbkzLb6Mw<&;$Svf+^zw literal 123 zcmeAS@N?(olHy`uVBq!ia0vp^96&6T9~r`OLZbQNE*4%WCorxxex$T+5VNm^P^F^3>p(;KP`_hD*T8(D%T5ZVS1c3=DcQ Wℜ!%(x6Rjlt8^&t;ucLK6U{Y9u`X From 07c4d2f4ca79561beb8a63e5ecc1579dd6fd0fd3 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 18 Sep 2025 14:21:42 -0400 Subject: [PATCH 34/62] v3.2.5: fixed thrown weapon merging not accounting for ID ready --- .../items/weapon/missiles/MissileWeapon.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java index 562e93c74..d2e558447 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/missiles/MissileWeapon.java @@ -539,9 +539,13 @@ abstract public class MissileWeapon extends Weapon { durability = MAX_DURABILITY; } - masteryPotionBonus = masteryPotionBonus || ((MissileWeapon) other).masteryPotionBonus; levelKnown = levelKnown || other.levelKnown; cursedKnown = cursedKnown || other.cursedKnown; + if (((Weapon)other).readyToIdentify()){ + setIDReady(); + } + + masteryPotionBonus = masteryPotionBonus || ((MissileWeapon) other).masteryPotionBonus; enchantHardened = enchantHardened || ((MissileWeapon) other).enchantHardened; //if other has a curse/enchant status that's a higher priority, copy it. in the following order: From 448d926d5a5b2965d2d4e84ae2ca9676d8d2c0d5 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 18 Sep 2025 14:44:21 -0400 Subject: [PATCH 35/62] v3.2.5: fixed metamorphed recall inscription text not being translated --- .../shatteredpixeldungeon/actors/hero/Talent.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java index 1ee8ad987..37607d03e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java @@ -773,7 +773,7 @@ public enum Talent { // 10/15% if (Random.Int(20) < 1 + hero.pointsInTalent(RECALL_INSCRIPTION)){ Reflection.newInstance(cls).collect(); - GLog.p("refunded!"); + GLog.p(Messages.get(Talent.class, RECALL_INSCRIPTION.name() + ".refunded")); } } } @@ -792,7 +792,7 @@ public enum Talent { // 10/15% if (Random.Int(20) < 1 + hero.pointsInTalent(RECALL_INSCRIPTION)){ Reflection.newInstance(cls).collect(); - GLog.p("refunded!"); + GLog.p(Messages.get(Talent.class, RECALL_INSCRIPTION.name() + ".refunded")); } } } From dad1d8009eded31522785b50f87322d9a4398ef8 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 18 Sep 2025 14:45:51 -0400 Subject: [PATCH 36/62] v3.2.5: fixed corruption DOT triggering DM-201s to attack --- .../shatteredpixeldungeon/actors/mobs/DM201.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DM201.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DM201.java index 435f534e2..757a67382 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DM201.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DM201.java @@ -25,6 +25,7 @@ import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob; import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.CorrosiveGas; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Corruption; import com.shatteredpixel.shatteredpixeldungeon.items.quest.MetalShard; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.sprites.DM201Sprite; @@ -52,9 +53,11 @@ public class DM201 extends DM200 { @Override public void damage(int dmg, Object src) { - if ((src instanceof Char && !Dungeon.level.adjacent(pos, ((Char)src).pos)) - || enemy == null || !Dungeon.level.adjacent(pos, enemy.pos)){ - threatened = true; + if (!(src instanceof Corruption)) { + if ((src instanceof Char && !Dungeon.level.adjacent(pos, ((Char) src).pos)) + || enemy == null || !Dungeon.level.adjacent(pos, enemy.pos)) { + threatened = true; + } } super.damage(dmg, src); } From 86ff1ab264c33fa4de5314706e3316784be33310 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 18 Sep 2025 15:30:20 -0400 Subject: [PATCH 37/62] v3.2.5: fixed cases where some walls were visible through fog of war --- .../shatteredpixeldungeon/tiles/WallBlockingTilemap.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/WallBlockingTilemap.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/WallBlockingTilemap.java index db3fcb51f..76c447fbe 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/WallBlockingTilemap.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/WallBlockingTilemap.java @@ -139,7 +139,7 @@ public class WallBlockingTilemap extends Tilemap { } else { //Block the side of an internal wall if: - //- the cell above, below, or the cell itself is visible + //- any cells above, the one directly below, or the cell itself is visible //and all of the following are NOT true: //- the cell has no neighbours on that side //- the top-side neighbour is visible and the side neighbour isn't a wall. @@ -149,6 +149,8 @@ public class WallBlockingTilemap extends Tilemap { curr = BLOCK_NONE; if (!fogHidden(cell - mapWidth) + || !fogHidden(cell - mapWidth - 1) + || !fogHidden(cell - mapWidth + 1) || !fogHidden(cell) || !fogHidden(cell + mapWidth)) { From 931fb362a3a46090a6cc5c1b1c5081c9e3ec1158 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sat, 20 Sep 2025 13:00:02 -0400 Subject: [PATCH 38/62] v3.2.5: Updated JDK used to package macOS version of Shattered - Fixes slow launches on newer macOS versions - Also removed "ShatteredPD" app title --- desktop/build.gradle | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/desktop/build.gradle b/desktop/build.gradle index 6b4709bb4..cfa3674ae 100644 --- a/desktop/build.gradle +++ b/desktop/build.gradle @@ -89,17 +89,17 @@ runtime { } } } else if (osName.contains('mac')) { + //Adoptium JDK 17 officially supports MacOS 12+, but internals suggest support for 10.12+ targetPlatform("mac") { - jdkHome = jdkDownload("https://github.com/AdoptOpenJDK/openjdk16-binaries/releases/download/jdk-16.0.1%2B9/OpenJDK16U-jdk_x64_mac_hotspot_16.0.1_9.tar.gz") - javaHome = file("./build/jdks/mac/jdk-16.0.1+9/Contents/Home/").getAbsolutePath() + jdkHome = jdkDownload("https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.16%2B8/OpenJDK17U-jdk_x64_mac_hotspot_17.0.16_8.tar.gz") + javaHome = file("./build/jdks/mac/jdk-17.0.16+8/Contents/Home/").getAbsolutePath() jpackage { - jpackageHome = file("./build/jdks/mac/jdk-16.0.1+9/Contents/Home/") + jpackageHome = file("./build/jdks/mac/jdk-17.0.16+8/Contents/Home/") imageOptions = ["--icon", file("./src/main/assets/icons/mac.icns"), "--java-options", "-XstartOnFirstThread", "--java-options", "-XX:+IgnoreUnrecognizedVMOptions", //append .apple because com.shatteredpixel.shatteredpixeldungeon was taken =( - "--mac-package-identifier", appPackageName + ".apple", - "--mac-package-name", "ShattererdPD"] + "--mac-package-identifier", appPackageName + ".apple"] } } } From 4deb71226acee29a06dd5440cd3fdaad36ba4543 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 21 Sep 2025 15:24:48 -0400 Subject: [PATCH 39/62] v3.2.5: added a button to hide the UI in the main menu --- .../scenes/TitleScene.java | 151 +++++++++++++++--- 1 file changed, 128 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java index 3b1b91069..eaaa65623 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java @@ -37,6 +37,7 @@ import com.shatteredpixel.shatteredpixeldungeon.services.updates.AvailableUpdate import com.shatteredpixel.shatteredpixeldungeon.services.updates.Updates; import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton; +import com.shatteredpixel.shatteredpixeldungeon.ui.IconButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton; import com.shatteredpixel.shatteredpixeldungeon.ui.TitleBackground; @@ -45,19 +46,41 @@ import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions; import com.shatteredpixel.shatteredpixeldungeon.windows.WndSettings; import com.shatteredpixel.shatteredpixeldungeon.windows.WndVictoryCongrats; import com.watabou.glwrap.Blending; +import com.watabou.input.PointerEvent; import com.watabou.noosa.BitmapText; import com.watabou.noosa.Camera; import com.watabou.noosa.Game; import com.watabou.noosa.Image; +import com.watabou.noosa.PointerArea; import com.watabou.noosa.audio.Music; +import com.watabou.noosa.tweeners.Tweener; import com.watabou.utils.ColorMath; import com.watabou.utils.DeviceCompat; +import com.watabou.utils.GameMath; import com.watabou.utils.RectF; import java.util.Date; public class TitleScene extends PixelScene { - + + private Image title; + private Fireball leftFB; + private Fireball rightFB; + private Image signs; + + private StyledButton btnPlay; + private StyledButton btnSupport; + private StyledButton btnRankings; + private StyledButton btnJournal; + private StyledButton btnNews; + private StyledButton btnChanges; + private StyledButton btnSettings; + private StyledButton btnAbout; + + private BitmapText version; + private IconButton btnFade; + private ExitButton btnExit; + @Override public void create() { @@ -81,7 +104,7 @@ public class TitleScene extends PixelScene { w -= insets.left + insets.right; h -= insets.top + insets.bottom; - Image title = BannerSprites.get( landscape() ? BannerSprites.Type.TITLE_LAND : BannerSprites.Type.TITLE_PORT); + title = BannerSprites.get( landscape() ? BannerSprites.Type.TITLE_LAND : BannerSprites.Type.TITLE_PORT); add( title ); float topRegion = Math.max(title.height - 6, h*0.45f); @@ -92,19 +115,20 @@ public class TitleScene extends PixelScene { align(title); if (landscape()){ - placeTorch(title.x + 30, title.y + 35); - placeTorch(title.x + title.width - 30, title.y + 35); + leftFB = placeTorch(title.x + 30, title.y + 35); + rightFB = placeTorch(title.x + title.width - 30, title.y + 35); } else { - placeTorch(title.x + 16, title.y + 70); - placeTorch(title.x + title.width - 16, title.y + 70); + leftFB = placeTorch(title.x + 16, title.y + 70); + rightFB = placeTorch(title.x + title.width - 16, title.y + 70); } - Image signs = new Image(BannerSprites.get( landscape() ? BannerSprites.Type.TITLE_GLOW_LAND : BannerSprites.Type.TITLE_GLOW_PORT)){ + signs = new Image(BannerSprites.get( landscape() ? BannerSprites.Type.TITLE_GLOW_LAND : BannerSprites.Type.TITLE_GLOW_PORT)){ private float time = 0; @Override public void update() { super.update(); am = Math.max(0f, (float)Math.sin( time += Game.elapsed )); + am = Math.min(am, title.am); if (time >= 1.5f*Math.PI) time = 0; } @Override @@ -120,7 +144,7 @@ public class TitleScene extends PixelScene { final Chrome.Type GREY_TR = Chrome.Type.GREY_BUTTON_TR; - StyledButton btnPlay = new StyledButton(GREY_TR, Messages.get(this, "enter")){ + btnPlay = new StyledButton(GREY_TR, Messages.get(this, "enter")){ @Override protected void onClick() { if (GamesInProgress.checkAll().size() == 0){ @@ -147,10 +171,10 @@ public class TitleScene extends PixelScene { btnPlay.icon(Icons.get(Icons.ENTER)); add(btnPlay); - StyledButton btnSupport = new SupportButton(GREY_TR, Messages.get(this, "support")); + btnSupport = new SupportButton(GREY_TR, Messages.get(this, "support")); add(btnSupport); - StyledButton btnRankings = new StyledButton(GREY_TR,Messages.get(this, "rankings")){ + btnRankings = new StyledButton(GREY_TR,Messages.get(this, "rankings")){ @Override protected void onClick() { ShatteredPixelDungeon.switchNoFade( RankingsScene.class ); @@ -160,27 +184,27 @@ public class TitleScene extends PixelScene { add(btnRankings); Dungeon.daily = Dungeon.dailyReplay = false; - StyledButton btnBadges = new StyledButton(GREY_TR, Messages.get(this, "journal")){ + btnJournal = new StyledButton(GREY_TR, Messages.get(this, "journal")){ @Override protected void onClick() { ShatteredPixelDungeon.switchNoFade( JournalScene.class ); } }; - btnBadges.icon(Icons.get(Icons.JOURNAL)); - add(btnBadges); + btnJournal.icon(Icons.get(Icons.JOURNAL)); + add(btnJournal); - StyledButton btnNews = new NewsButton(GREY_TR, Messages.get(this, "news")); + btnNews = new NewsButton(GREY_TR, Messages.get(this, "news")); btnNews.icon(Icons.get(Icons.NEWS)); add(btnNews); - StyledButton btnChanges = new ChangesButton(GREY_TR, Messages.get(this, "changes")); + btnChanges = new ChangesButton(GREY_TR, Messages.get(this, "changes")); btnChanges.icon(Icons.get(Icons.CHANGES)); add(btnChanges); - StyledButton btnSettings = new SettingsButton(GREY_TR, Messages.get(this, "settings")); + btnSettings = new SettingsButton(GREY_TR, Messages.get(this, "settings")); add(btnSettings); - StyledButton btnAbout = new StyledButton(GREY_TR, Messages.get(this, "about")){ + btnAbout = new StyledButton(GREY_TR, Messages.get(this, "about")){ @Override protected void onClick() { ShatteredPixelDungeon.switchScene( AboutScene.class ); @@ -201,8 +225,8 @@ public class TitleScene extends PixelScene { align(btnPlay); btnSupport.setRect(btnPlay.right()+2, btnPlay.top(), btnPlay.width(), BTN_HEIGHT); btnRankings.setRect(btnPlay.left(), btnPlay.bottom()+ GAP, (float) (Math.floor(buttonAreaWidth/3f)-1), BTN_HEIGHT); - btnBadges.setRect(btnRankings.right()+2, btnRankings.top(), btnRankings.width(), BTN_HEIGHT); - btnNews.setRect(btnBadges.right()+2, btnBadges.top(), btnRankings.width(), BTN_HEIGHT); + btnJournal.setRect(btnRankings.right()+2, btnRankings.top(), btnRankings.width(), BTN_HEIGHT); + btnNews.setRect(btnJournal.right()+2, btnJournal.top(), btnRankings.width(), BTN_HEIGHT); btnSettings.setRect(btnRankings.left(), btnRankings.bottom() + GAP, btnRankings.width(), BTN_HEIGHT); btnChanges.setRect(btnSettings.right()+2, btnSettings.top(), btnRankings.width(), BTN_HEIGHT); btnAbout.setRect(btnChanges.right()+2, btnSettings.top(), btnRankings.width(), BTN_HEIGHT); @@ -211,22 +235,65 @@ public class TitleScene extends PixelScene { align(btnPlay); btnSupport.setRect(btnPlay.left(), btnPlay.bottom()+ GAP, btnPlay.width(), BTN_HEIGHT); btnRankings.setRect(btnPlay.left(), btnSupport.bottom()+ GAP, (btnPlay.width()/2)-1, BTN_HEIGHT); - btnBadges.setRect(btnRankings.right()+2, btnRankings.top(), btnRankings.width(), BTN_HEIGHT); + btnJournal.setRect(btnRankings.right()+2, btnRankings.top(), btnRankings.width(), BTN_HEIGHT); btnNews.setRect(btnRankings.left(), btnRankings.bottom()+ GAP, btnRankings.width(), BTN_HEIGHT); btnChanges.setRect(btnNews.right()+2, btnNews.top(), btnNews.width(), BTN_HEIGHT); btnSettings.setRect(btnNews.left(), btnNews.bottom()+GAP, btnRankings.width(), BTN_HEIGHT); btnAbout.setRect(btnSettings.right()+2, btnSettings.top(), btnSettings.width(), BTN_HEIGHT); } - BitmapText version = new BitmapText( "v" + Game.version, pixelFont); + version = new BitmapText( "v" + Game.version, pixelFont); version.measure(); version.hardlight( 0x888888 ); version.x = insets.left + w - version.width() - (DeviceCompat.isDesktop() ? 4 : 8); version.y = insets.top + h - version.height() - (DeviceCompat.isDesktop() ? 2 : 4); add( version ); + btnFade = new IconButton(Icons.CHEVRON.get()){ + @Override + protected void onClick() { + enable(false); + parent.add(new Tweener(parent, 0.5f) { + @Override + protected void updateValues(float progress) { + if (!btnFade.active) { + uiAlpha = 1 - progress; + updateFade(); + } + } + }); + } + }; + btnFade.icon().originToCenter(); + btnFade.icon().angle = 180f; + btnFade.setRect(btnAreaLeft + (buttonAreaWidth-16)/2, btnAbout.bottom() + GAP/2 + 2, 16, 10); + if (btnFade.bottom() > camera.main.height){ + btnFade.setPos(btnFade.left(), btnFade.top() - (btnFade.bottom()-camera.main.height)); + } + add(btnFade); + + PointerArea fadeResetter = new PointerArea(0, 0, Camera.main.width, Camera.main.height){ + @Override + public boolean onSignal(PointerEvent event) { + if (event != null && event.type == PointerEvent.Type.UP && !btnPlay.active){ + parent.add(new Tweener(parent, 0.5f) { + @Override + protected void updateValues(float progress) { + uiAlpha = progress; + updateFade(); + if (progress >= 1){ + btnFade.enable(true); + } + } + }); + } + return false; + } + }; + add(fadeResetter); + if (DeviceCompat.isDesktop()) { - ExitButton btnExit = new ExitButton(); + btnExit = new ExitButton(); btnExit.setPos( w - btnExit.width(), 0 ); add( btnExit ); } @@ -240,13 +307,51 @@ public class TitleScene extends PixelScene { fadeIn(); } - private void placeTorch( float x, float y ) { + private float uiAlpha; + + public void updateFade() { + float alpha = GameMath.gate(0f, uiAlpha, 1f); + + title.am = alpha; + leftFB.am = alpha; + rightFB.am = alpha; + //signs.am = alpha; handles this itself + + btnPlay.enable(alpha != 0); + btnSupport.enable(alpha != 0); + btnRankings.enable(alpha != 0); + btnJournal.enable(alpha != 0); + btnNews.enable(alpha != 0); + btnChanges.enable(alpha != 0); + btnSettings.enable(alpha != 0); + btnAbout.enable(alpha != 0); + + btnPlay.alpha(alpha); + btnSupport.alpha(alpha); + btnRankings.alpha(alpha); + btnJournal.alpha(alpha); + btnNews.alpha(alpha); + btnChanges.alpha(alpha); + btnSettings.alpha(alpha); + btnAbout.alpha(alpha); + + version.alpha(alpha); + btnFade.icon().alpha(alpha); + if (btnExit != null){ + btnExit.enable(alpha != 0); + btnExit.icon().alpha(alpha); + } + + } + + private Fireball placeTorch(float x, float y ) { Fireball fb = new Fireball(); fb.x = x - fb.width()/2f; fb.y = y - fb.height(); align(fb); add( fb ); + return fb; } private static class NewsButton extends StyledButton { From c645462651b13e4ea6616cbc7a8b16fc0a3a7fdd Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 21 Sep 2025 15:46:11 -0400 Subject: [PATCH 40/62] v3.2.5: adjusted the style of version info to look less like an HP bar --- core/src/main/assets/interfaces/menu_pane.png | Bin 242 -> 247 bytes .../shatteredpixeldungeon/ui/MenuPane.java | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/assets/interfaces/menu_pane.png b/core/src/main/assets/interfaces/menu_pane.png index cc6d1d92f5e632e8d9f37fd608f41d86d61ac9e8..84c1f07ba0978c5a558cfcfd89184bd41d7eb3b0 100644 GIT binary patch delta 231 zcmV9D>001*kOjJbx004V{b7*W~RasDTcxcgY{h^+vl1lAvFL1002ovPDHLkV1nNoV}bwx delta 226 zcmey)_=$0XL_G^L0|P^2NcwRgr5@lD;tHgz8;Ub>5ciYsy!FPo~WuBf7>prxa# zsjZ@+ZZrg zQlcl2k=cr&br*w?yoemziJE{F>I=ALl$$KzJTs?3D`9IEBT(WM?_(E7}5G!QkoY=d#Wzp$PzB;zgtY diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java index c0c9a5343..00c6cb623 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/MenuPane.java @@ -82,7 +82,7 @@ public class MenuPane extends Component { add(versionOverflowBG); version = new BitmapText( "v" + Game.version , PixelScene.pixelFont); - version.alpha( 0.5f ); + version.hardlight( 0xCACFC2 ); add(version); depthIcon = Icons.get(Dungeon.level.feeling); From 5bbcf99e8fa85445a0c721f6e752dde10efe4dba Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 21 Sep 2025 16:28:11 -0400 Subject: [PATCH 41/62] v3.2.5: adjusted new title fade button to align with bottom of the scene --- .../shatteredpixeldungeon/scenes/TitleScene.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java index eaaa65623..ddd6fceb8 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java @@ -266,10 +266,7 @@ public class TitleScene extends PixelScene { }; btnFade.icon().originToCenter(); btnFade.icon().angle = 180f; - btnFade.setRect(btnAreaLeft + (buttonAreaWidth-16)/2, btnAbout.bottom() + GAP/2 + 2, 16, 10); - if (btnFade.bottom() > camera.main.height){ - btnFade.setPos(btnFade.left(), btnFade.top() - (btnFade.bottom()-camera.main.height)); - } + btnFade.setRect(btnAreaLeft + (buttonAreaWidth-16)/2, camera.main.height - 16, 16, 16); add(btnFade); PointerArea fadeResetter = new PointerArea(0, 0, Camera.main.width, Camera.main.height){ From 1b82e52f350784a7c58a4b7eb2ac730ae259383b Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Mon, 22 Sep 2025 12:01:53 -0400 Subject: [PATCH 42/62] v3.2.5: added a new larger boss HP bar for full size UI --- core/src/main/assets/interfaces/boss_hp.png | Bin 402 -> 871 bytes .../scenes/GameScene.java | 2 +- .../ui/BossHealthBar.java | 80 ++++++++++++------ 3 files changed, 57 insertions(+), 25 deletions(-) diff --git a/core/src/main/assets/interfaces/boss_hp.png b/core/src/main/assets/interfaces/boss_hp.png index b664ac59211f9dd5239391d0d2f9f0be187e2aa5..50e4f2dca33745a0b1aa9fa8c1d47351d95015de 100644 GIT binary patch literal 871 zcmV-t1DO1YP)pIisePpr)1O+QZDkt(h(^dw_FQSx|$BdH?_bii35AC@&=^A#!bDv#OYLA}}N- zASWp!Dl8=tJvTQwGdesrHaIdpKR7ivF+4suG&V3h zJvK8nFFHImGBhqZJ2WvfEjT(eFfuGRIWjLXD>gVWE-)%JH!v+PDKs`OEG{TBH7+YH zCo(iGDl8^3Gb|}9B``88C@Lf`F)A)FDJ?H3EG{Q2Eheo(G>|JVeI+nyA1q-VDZ;|S zot>S8goJBrYhPbqfPx4%00001bW%=J06^y0W&i*J0ZBwbRCodG)=6hQ1PHMzF+dhWqRa`5 z!U=)w2~kQI2)<;neE{MJehgf6fGqjCRM3cE+jg zj*Um`P|rUGM@p9-V{loh=jVg5kkaeAHq(;NZ6ih~Oq1OOO{g0G|#;xZpDG2GpD zLN;jhr*{REzQnL1S`%VEBbSxX8WZz1xvY%Vh?wulWfioB#EdFR1Bf|iQdteHJ~6+L x%j#(Li1~wD)W1Rb z$bjaKDphqw6*UEQO=T?|Rb^FqH4PY7S+4wmwY z(rOxtatcza>I$;*k}`4<|3BY+dh76+Lu>a3SON|2YA&6rr&pAlxOvr#HVyq^C4(C` zZme9nvcJE-qN2iGfKL;sh^ZvVFPK59`=f~ykhjm%#WAFU@$LmvrVvK~mJ8vRd$apm z@BFt&u~2;Xx;y>M@yf#N)(v;IJ<(R){AD4xgPCD!@`R5!wUYUISvK_Y2%GVQJYCT> z%X#s=c`Wb!0@Fl#mpDACnfD_vagFretbn!ir$}n|u3`$E7cq0=RS8Lj=BwA{9D7l| zpuMtp&bFA{e;x@oBt|V^)ah{GVA%FAGW@%aP=V=**gFPK``EO$Noy3>U2FIq&R(uK uZRfGldbgU_%QUxd$v?Wp-u{9824>$E$_^Jr%%y-nVeoYIb6Mw<&;$Usb(T5+ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index 201963180..fbe76f024 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -459,7 +459,7 @@ public class GameScene extends PixelScene { boss = new BossHealthBar(); boss.camera = uiCamera; - boss.setPos( (uiCamera.width - boss.width())/2, screentop + 26); + boss.setPos( (uiCamera.width - boss.width())/2, screentop + uiSize == 0 ? 26 : 7); add(boss); resume = new ResumeIndicator(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BossHealthBar.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BossHealthBar.java index 2995f626b..61a02ab5d 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BossHealthBar.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BossHealthBar.java @@ -23,6 +23,8 @@ package com.shatteredpixel.shatteredpixeldungeon.ui; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.SPDSettings; +import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.effects.particles.BloodParticle; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; @@ -32,6 +34,7 @@ import com.watabou.noosa.BitmapText; import com.watabou.noosa.Image; import com.watabou.noosa.particles.Emitter; import com.watabou.noosa.ui.Component; +import com.watabou.utils.Callback; public class BossHealthBar extends Component { @@ -55,6 +58,8 @@ public class BossHealthBar extends Component { private static BossHealthBar instance; private static boolean bleeding; + private boolean large; + public BossHealthBar() { super(); visible = active = (boss != null); @@ -70,20 +75,22 @@ public class BossHealthBar extends Component { @Override protected void createChildren() { - bar = new Image(asset, 0, 0, 64, 16); + this.large = SPDSettings.interfaceSize() != 0; + + bar = large ? new Image(asset, 0, 16, 128, 30) : new Image(asset, 0, 0, 64, 16); add(bar); width = bar.width; height = bar.height; - rawShielding = new Image(asset, 15, 25, 47, 4); + rawShielding = large ? new Image(asset, 0, 55, 96, 9) : new Image(asset, 71, 5, 47, 4); rawShielding.alpha(0.5f); add(rawShielding); - shieldedHP = new Image(asset, 15, 25, 47, 4); + shieldedHP = large ? new Image(asset, 0, 55, 96, 9) : new Image(asset, 71, 5, 47, 4); add(shieldedHP); - hp = new Image(asset, 15, 19, 47, 4); + hp = large ? new Image(asset, 0, 46, 96, 9) : new Image(asset, 71, 0, 47, 4); add(hp); hpText = new BitmapText(PixelScene.pixelFont); @@ -110,12 +117,16 @@ public class BossHealthBar extends Component { add(bossInfo); if (boss != null) { - buffs = new BuffIndicator(boss, false); + buffs = new BuffIndicator(boss, large); BuffIndicator.setBossInstance(buffs); add(buffs); } - skull = new Image(asset, 5, 18, 6, 6); + if (boss != null && large) { + skull = boss.sprite(); + } else { + skull = new Image(asset, 64, 0, 6, 6); + } add(skull); blood = new Emitter(); @@ -131,11 +142,11 @@ public class BossHealthBar extends Component { bar.x = x; bar.y = y; - hp.x = shieldedHP.x = rawShielding.x = bar.x+15; - hp.y = shieldedHP.y = rawShielding.y = bar.y+3; + hp.x = shieldedHP.x = rawShielding.x = bar.x+(large ? 30 : 15); + hp.y = shieldedHP.y = rawShielding.y = bar.y+(large ? 2 : 3); - hpText.scale.set(PixelScene.align(0.5f)); - hpText.x = hp.x + 1; + if (!large) hpText.scale.set(PixelScene.align(0.5f)); + hpText.x = hp.x + (large ? (96-hpText.width())/2f : 1); hpText.y = hp.y + (hp.height - (hpText.baseLine()+hpText.scale.y))/2f; hpText.y -= 0.001f; //prefer to be slightly higher PixelScene.align(hpText); @@ -143,11 +154,16 @@ public class BossHealthBar extends Component { bossInfo.setRect(x, y, bar.width, bar.height); if (buffs != null) { - buffs.setRect(hp.x, hp.y + 5, 47, 8); + if (large) { + buffs.setRect(hp.x+1, hp.y + 12, 80, 16); + } else { + buffs.setRect(hp.x, hp.y + 5, 40, 7); + } } - skull.x = bar.x+5; - skull.y = bar.y+5; + int paneSize = large ? 30 : 16; + skull.x = bar.x + (paneSize - skull.width())/2f; + skull.y = bar.y + (paneSize - skull.height())/2f; } @Override @@ -174,8 +190,10 @@ public class BossHealthBar extends Component { rawShielding.scale.x = shield/(float)max; if (bleeding != blood.on){ - if (bleeding) skull.tint( 0xcc0000, 0.6f ); + if (bleeding) skull.tint( 0xcc0000, large ? 0.3f : 0.6f ); else skull.resetColor(); + bringToFront(blood); + blood.pos(skull); blood.on = bleeding; } @@ -184,6 +202,7 @@ public class BossHealthBar extends Component { } else { hpText.text(health + "+" + shield + "/" + max); } + hpText.x = hp.x + (large ? (96-hpText.width())/2f : 1); } } @@ -196,17 +215,30 @@ public class BossHealthBar extends Component { BossHealthBar.boss = boss; bleed(false); if (instance != null) { - instance.visible = instance.active = true; - if (boss != null){ - if (instance.buffs != null){ - instance.remove(instance.buffs); - instance.buffs.destroy(); + ShatteredPixelDungeon.runOnRenderThread(new Callback() { + @Override + public void call() { + instance.visible = instance.active = true; + if (boss != null){ + if (instance.large){ + if (instance.skull != null){ + instance.remove(instance.skull); + instance.skull.destroy(); + } + instance.skull = boss.sprite(); + instance.add(instance.skull); + } + if (instance.buffs != null){ + instance.remove(instance.buffs); + instance.buffs.destroy(); + } + instance.buffs = new BuffIndicator(boss, instance.large); + BuffIndicator.setBossInstance(instance.buffs); + instance.add(instance.buffs); + instance.layout(); + } } - instance.buffs = new BuffIndicator(boss, false); - BuffIndicator.setBossInstance(instance.buffs); - instance.add(instance.buffs); - instance.layout(); - } + }); } } From 41905ba6c62218e094a8911ecc5c2a68333d5fc0 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Mon, 22 Sep 2025 18:22:35 -0400 Subject: [PATCH 43/62] v3.2.5: cleaned up some code and logic relating to buff indicators This fixes some errors in enemy info windows, cases of cutouts cutting off some buffs, and lets more buffs appear in mob info windows --- .../scenes/GameScene.java | 9 +++--- .../ui/BossHealthBar.java | 6 ++-- .../ui/BuffIndicator.java | 28 +++++++++---------- .../shatteredpixeldungeon/ui/StatusPane.java | 5 ++-- .../windows/WndInfoMob.java | 19 ++++++------- 5 files changed, 35 insertions(+), 32 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index fbe76f024..a64229a51 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -372,14 +372,14 @@ public class GameScene extends PixelScene { float heroPaneExtraWidth = insets.left; float menuBarMaxLeft = uiCamera.width-insets.right-MenuPane.WIDTH; int hpBarMaxWidth = 50; //default max width - float buffBarTopRowMaxWidth = 50; //default max width + float buffBarTopRowMaxWidth = 55; //default max width if (largeInsetTop == 0){ //iOS's Dynamic island badly obstructs the first buff bar row if (DeviceCompat.isiOS()){ //TODO bad to hardcode and approximate this atm // need to change this so iOS platformsupport returns cutout dimensions float cutoutLeft = (Game.width*0.3f)/defaultZoom; - buffBarTopRowMaxWidth = Math.min(50, cutoutLeft - 32); + buffBarTopRowMaxWidth = Math.min(55, cutoutLeft - 32); } else if (DeviceCompat.isAndroid()) { //Android hole punches are of varying size and may obstruct various UI elements RectF cutout = Game.platform.getDisplayCutout().scale(1f / defaultZoom); @@ -408,11 +408,12 @@ public class GameScene extends PixelScene { hpBarMaxWidth = Math.max(hpBarMaxWidth, 21); //cannot go below 21 (30 effective) } //if the cutout is positioned to obstruct the buff bar - if (cutout.left < 80 + if (cutout.left < 84 && cutout.top < 10 && cutout.right > 32 && cutout.bottom > 11) { - buffBarTopRowMaxWidth = cutout.left - 32; //subtract starting position + //subtract starting position, add a bit back to allow slight overlap + buffBarTopRowMaxWidth = cutout.left - 32 + 3; } } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BossHealthBar.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BossHealthBar.java index 61a02ab5d..867bbd6a5 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BossHealthBar.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BossHealthBar.java @@ -154,10 +154,12 @@ public class BossHealthBar extends Component { bossInfo.setRect(x, y, bar.width, bar.height); if (buffs != null) { + buffs.maxBuffs = 12; if (large) { - buffs.setRect(hp.x+1, hp.y + 12, 80, 16); + //little extra width here for a 6th column + buffs.setRect(hp.x+1, hp.y + 12, 102, 34); } else { - buffs.setRect(hp.x, hp.y + 5, 40, 7); + buffs.setRect(hp.x, hp.y + 5, 47, 16); } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java index 6f44e9de0..52149eccf 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java @@ -180,6 +180,7 @@ public class BuffIndicator extends Component { } private boolean buffsHidden = false; + public int maxBuffs = 14; //by default @Override protected void layout() { @@ -228,32 +229,29 @@ public class BuffIndicator extends Component { } } - //TODO several aspects of the layout code have been a bit hackily changed to support 2 rows - // should clean this up - //layout - int row = 0; + int row = 1; int pos = 0; - float lastIconLeft = 0; + float lastIconRight = 0; int total = 0; for (BuffButton icon : buffButtons.values()){ - if (total >= 14){ //buff bar supports a max of 14 buffs at once + if (total >= maxBuffs){ icon.visible = false; continue; } icon.visible = true; - icon.topOffset = (row > 0 && !large) ? -1 : 0; + icon.topOffset = (row > 1 && !large) ? -1 : 0; icon.updateIcon(); //button areas are slightly oversized, especially on small buttons - icon.setRect(x + pos * (size + 1), y + row*(size+1)-icon.topOffset, size + 1, size + (large ? 0 : 5)); + icon.setRect(x + pos * (size + 1), y + (row-1)*(size+1)-icon.topOffset, size + 1, size + (large ? 0 : 5)); PixelScene.align(icon); pos++; - lastIconLeft = icon.left(); + lastIconRight = icon.right()-1; if ((row+1)*(size+1) <= height - && (pos * (size + 1) > width || (row == 0 && firstRowWidth != -1 && pos * (size + 1) > firstRowWidth))){ + && (pos * (size + 1) + size > width || (row == 1 && firstRowWidth != -1 && pos * (size + 1) + size > firstRowWidth))){ row++; pos = 0; } @@ -262,15 +260,15 @@ public class BuffIndicator extends Component { buffsHidden = false; //squish buff icons together if there isn't enough room - float excessWidth = lastIconLeft - right(); + float excessWidth = lastIconRight - right(); if (excessWidth > 0) { //if multiple rows, only compress last row ArrayList buttons = new ArrayList<>(); - float lastRowY = y + row*(size+1); + float lastRowY = PixelScene.align(y + (row-1)*(size+1)); int i = 1; for (BuffButton button : buffButtons.values()){ - if (i > 14){ + if (i > maxBuffs){ button.visible = false; buffsHidden = true; continue; @@ -282,12 +280,14 @@ public class BuffIndicator extends Component { } float leftAdjust = excessWidth/(buttons.size()-1); + //can't squish by more than 50% + if (leftAdjust >= size*0.48f) leftAdjust = size*0.5f; float cumulativeAdjust = leftAdjust * (buttons.size()-1); Collections.reverse(buttons); for (BuffButton icon : buttons) { icon.setPos(icon.left() - cumulativeAdjust, icon.top()); - icon.visible = icon.left() <= right(); + icon.visible = icon.right() <= right()+1; if (!icon.visible) buffsHidden = true; PixelScene.align(icon); bringToFront(icon); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java index ac226cde8..19a9bf4f4 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java @@ -222,7 +222,8 @@ public class StatusPane extends Component { heroInfoOnBar.setRect(heroInfo.right(), y + 19, 130, 20); - buffs.setRect(x + 31, y, 128, 16); + //little extra for 14th buff + buffs.setRect(x + 31, y, 142, 16); busy.x = x + bg.width + 1; busy.y = y + bg.height - 9; @@ -271,7 +272,7 @@ public class StatusPane extends Component { heroInfoOnBar.setRect(heroInfo.right(), y, 50, 9); buffs.firstRowWidth = buffBarTopRowMaxWidth; - buffs.setRect( x + heroPaneWidth + 1, y + 8, 50, 15 ); + buffs.setRect( x + heroPaneWidth + 1, y + 8, 55, 16 ); busy.x = x + 1; busy.y = y + 37; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoMob.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoMob.java index 619bf7005..5af1288a2 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoMob.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoMob.java @@ -71,23 +71,22 @@ public class WndInfoMob extends WndTitledMessage { image.y = Math.max( 0, name.height() + health.height() - image.height() ); float w = width - image.width() - GAP; - int extraBuffSpace = 0; - - //Tries to make space for up to 11 visible buffs - do { - name.maxWidth((int)w - extraBuffSpace); - buffs.setSize(w - name.width() - 8, 8); - extraBuffSpace += 8; - } while (extraBuffSpace <= 40 && !buffs.allBuffsVisible()); name.setPos(x + image.width() + GAP, image.height() > name.height() ? y +(image.height() - name.height()) / 2 : y); health.setRect(image.width() + GAP, name.bottom() + GAP, w, health.height()); - buffs.setPos(name.right(), name.bottom() - BuffIndicator.SIZE_SMALL-2); + buffs.maxBuffs = 50; //infinite, effectively + buffs.setRect(name.right(), name.bottom() - BuffIndicator.SIZE_SMALL-2, w - name.width(), 8); - height = Math.max(image.y + image.height(), health.bottom()); + //If buff bar doesn't have enough room, move it below + if (!buffs.allBuffsVisible()){ + buffs.setRect(0, health.bottom(), width, 8); + height = Math.max(image.y + image.height(), buffs.bottom()); + } else { + height = Math.max(image.y + image.height(), health.bottom()); + } } } } From 5073777610b96cf8b213183b9be8023216741b58 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Mon, 22 Sep 2025 18:48:09 -0400 Subject: [PATCH 44/62] v3.2.5: adjusted shielding to display in addition to HP, not on top --- .../scenes/GameScene.java | 2 +- .../ui/BossHealthBar.java | 30 +++++++------ .../shatteredpixeldungeon/ui/StatusPane.java | 43 ++++++++----------- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index a64229a51..b8e258b83 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -460,7 +460,7 @@ public class GameScene extends PixelScene { boss = new BossHealthBar(); boss.camera = uiCamera; - boss.setPos( (uiCamera.width - boss.width())/2, screentop + uiSize == 0 ? 26 : 7); + boss.setPos( (uiCamera.width - boss.width())/2, screentop + (landscape() ? 7 : 26)); add(boss); resume = new ResumeIndicator(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BossHealthBar.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BossHealthBar.java index 867bbd6a5..2ef11f2d8 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BossHealthBar.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BossHealthBar.java @@ -40,8 +40,7 @@ public class BossHealthBar extends Component { private Image bar; - private Image rawShielding; - private Image shieldedHP; + private Image shieldHP; private Image hp; private BitmapText hpText; @@ -83,12 +82,8 @@ public class BossHealthBar extends Component { width = bar.width; height = bar.height; - rawShielding = large ? new Image(asset, 0, 55, 96, 9) : new Image(asset, 71, 5, 47, 4); - rawShielding.alpha(0.5f); - add(rawShielding); - - shieldedHP = large ? new Image(asset, 0, 55, 96, 9) : new Image(asset, 71, 5, 47, 4); - add(shieldedHP); + shieldHP = large ? new Image(asset, 0, 55, 96, 9) : new Image(asset, 71, 5, 47, 4); + add(shieldHP); hp = large ? new Image(asset, 0, 46, 96, 9) : new Image(asset, 71, 0, 47, 4); add(hp); @@ -142,8 +137,8 @@ public class BossHealthBar extends Component { bar.x = x; bar.y = y; - hp.x = shieldedHP.x = rawShielding.x = bar.x+(large ? 30 : 15); - hp.y = shieldedHP.y = rawShielding.y = bar.y+(large ? 2 : 3); + hp.x = shieldHP.x = bar.x+(large ? 30 : 15); + hp.y = shieldHP.y = bar.y+(large ? 2 : 3); if (!large) hpText.scale.set(PixelScene.align(0.5f)); hpText.x = hp.x + (large ? (96-hpText.width())/2f : 1); @@ -187,9 +182,17 @@ public class BossHealthBar extends Component { int shield = boss.shielding(); int max = boss.HT; - hp.scale.x = Math.max( 0, (health-shield)/(float)max); - shieldedHP.scale.x = health/(float)max; - rawShielding.scale.x = shield/(float)max; + float healthPercent = health/(float)max; + float shieldPercent = shield/(float)max; + + if (healthPercent + shieldPercent > 1f){ + float excess = healthPercent + shieldPercent; + healthPercent /= excess; + shieldPercent /= excess; + } + + hp.scale.x = healthPercent; + shieldHP.scale.x = healthPercent + shieldPercent; if (bleeding != blood.on){ if (bleeding) skull.tint( 0xcc0000, large ? 0.3f : 0.6f ); @@ -204,6 +207,7 @@ public class BossHealthBar extends Component { } else { hpText.text(health + "+" + shield + "/" + max); } + hpText.measure(); hpText.x = hp.x + (large ? (96-hpText.width())/2f : 1); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java index 19a9bf4f4..fd0af2094 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java @@ -57,8 +57,7 @@ public class StatusPane extends Component { private int lastTier = 0; - private Image rawShielding; - private Image shieldedHP; + private Image shieldHP; private Image hp; private BitmapText hpText; private Button heroInfoOnBar; @@ -133,14 +132,9 @@ public class StatusPane extends Component { compass = new Compass( Statistics.amuletObtained ? Dungeon.level.entrance() : Dungeon.level.exit() ); add( compass ); - if (large) rawShielding = new Image(asset, 0, 112, 128, 9); - else rawShielding = new Image(asset, 0, 44, 50, 4); - rawShielding.alpha(0.5f); - add(rawShielding); - - if (large) shieldedHP = new Image(asset, 0, 112, 128, 9); - else shieldedHP = new Image(asset, 0, 44, 50, 4); - add(shieldedHP); + if (large) shieldHP = new Image(asset, 0, 112, 128, 9); + else shieldHP = new Image(asset, 0, 44, 50, 4); + add(shieldHP); if (large) hp = new Image(asset, 0, 103, 128, 9); else hp = new Image(asset, 0, 40, 50, 4); @@ -209,8 +203,8 @@ public class StatusPane extends Component { exp.x = x + 30; exp.y = y + 30; - hp.x = shieldedHP.x = rawShielding.x = x + 30; - hp.y = shieldedHP.y = rawShielding.y = y + 19; + hp.x = shieldHP.x = x + 30; + hp.y = shieldHP.y = y + 19; hpText.x = hp.x + (128 - hpText.width())/2f; hpText.y = hp.y + 1; @@ -250,12 +244,11 @@ public class StatusPane extends Component { hpCutout.y = y; } hp.frame(50-hpWidth, 40, 50, 4); - shieldedHP.frame(50-hpWidth, 44, 50, 4); - rawShielding.frame(50-hpWidth, 44, 50, 4); + shieldHP.frame(50-hpWidth, 44, 50, 4); } - hp.x = shieldedHP.x = rawShielding.x = hpleft; - hp.y = shieldedHP.y = rawShielding.y = y + 2; + hp.x = shieldHP.x = hpleft; + hp.y = shieldHP.y = y + 2; hpText.scale.set(PixelScene.align(0.5f)); hpText.x = hp.x + 1; @@ -308,15 +301,18 @@ public class StatusPane extends Component { avatar.resetColor(); } - hp.scale.x = Math.max( 0, (health-shield)/(float)max); - shieldedHP.scale.x = health/(float)max; + float healthPercent = health/(float)max; + float shieldPercent = shield/(float)max; - if (shield > health) { - rawShielding.scale.x = Math.min(1, shield / (float) max); - } else { - rawShielding.scale.x = 0; + if (healthPercent + shieldPercent > 1f){ + float excess = healthPercent + shieldPercent; + healthPercent /= excess; + shieldPercent /= excess; } + hp.scale.x = healthPercent; + shieldHP.scale.x = healthPercent + shieldPercent; + if (oldHP != health || oldShield != shield || oldMax != max){ if (shield <= 0) { hpText.text(health + "/" + max); @@ -384,8 +380,7 @@ public class StatusPane extends Component { heroPaneCutout.alpha(value); hpCutout.alpha(value); avatar.alpha(value); - rawShielding.alpha(0.5f*value); - shieldedHP.alpha(value); + shieldHP.alpha(value); hp.alpha(value); hpText.alpha(0.6f*value); exp.alpha(value); From b8e00af98a9a81a32a8d039278713de73318e2c2 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Tue, 23 Sep 2025 18:25:30 -0400 Subject: [PATCH 45/62] v3.2.5: adjusted iOS dynamic island handling for buff indicator change --- .../shatteredpixeldungeon/scenes/GameScene.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index b8e258b83..b8c2dbe97 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -378,8 +378,11 @@ public class GameScene extends PixelScene { if (DeviceCompat.isiOS()){ //TODO bad to hardcode and approximate this atm // need to change this so iOS platformsupport returns cutout dimensions - float cutoutLeft = (Game.width*0.3f)/defaultZoom; - buffBarTopRowMaxWidth = Math.min(55, cutoutLeft - 32); + // which would also help with detecting if the cutout is big enough to put into 2nd row =S + //note that the island is a bit smaller in terms of screen % on bigger iPhones + // we try to average that a bit here + float cutoutLeft = (Game.width*0.34f)/defaultZoom; + buffBarTopRowMaxWidth = Math.min(55, cutoutLeft - 32 + 3); } else if (DeviceCompat.isAndroid()) { //Android hole punches are of varying size and may obstruct various UI elements RectF cutout = Game.platform.getDisplayCutout().scale(1f / defaultZoom); From 19363d81884eb21b9836884a6a86cf491a953eb2 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Wed, 24 Sep 2025 13:34:45 -0400 Subject: [PATCH 46/62] v3.2.5: fixed a couple missing periods --- core/src/main/assets/messages/actors/actors.properties | 2 +- core/src/main/assets/messages/items/items.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index f7f2598c6..fcc6cfa6a 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -486,7 +486,7 @@ actors.hero.abilities.mage.warpbeacon.short_desc=The Mage places a _Warping Beac actors.hero.abilities.mage.warpbeacon.desc=The Mage places a beacon, which can then be warped to at will. Placing the beacon takes 1 turn, but warping to it is instantaneous.\n\nThe Mage cannot warp between floors by default, or use the beacon to reach inaccessible places such as locked rooms. The Mage can teleport into enemies, which will push them aside. actors.hero.abilities.rogue.smokebomb.name=smoke bomb -actors.hero.abilities.rogue.smokebomb.fov=You can only jump to an empty location in your field of view +actors.hero.abilities.rogue.smokebomb.fov=You can only jump to an empty location in your field of view. actors.hero.abilities.rogue.smokebomb.prompt=Choose a location to jump to actors.hero.abilities.rogue.smokebomb$ninjalog.name=wooden decoy actors.hero.abilities.rogue.smokebomb$ninjalog.desc=Somehow, enemies are easily convinced that this wooden decoy is the real Rogue! diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index 0577e67a7..8fb4f37f6 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -392,7 +392,7 @@ items.artifacts.masterthievesarmband.no_charge=Your armband does not have enough items.artifacts.masterthievesarmband.cursed=You can't use a cursed armband. items.artifacts.masterthievesarmband.full=Your armband is fully charged! items.artifacts.masterthievesarmband.prompt=Choose an enemy to target -items.artifacts.masterthievesarmband.no_target=You must target an enemy that is adjacent to you +items.artifacts.masterthievesarmband.no_target=You must target an enemy that is adjacent to you. items.artifacts.masterthievesarmband.steal_shopkeeper=You can't steal from shopkeepers directly. items.artifacts.masterthievesarmband.no_steal=That enemy has nothing to steal. items.artifacts.masterthievesarmband.stole_item=You stole an item: %s. From 0cce050429d129b215c98ac484cb7aba6ef8050c Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Wed, 24 Sep 2025 16:29:52 -0400 Subject: [PATCH 47/62] v3.2.5: fixed very specific errors relating to inter-floor teleports --- .../items/spells/BeaconOfReturning.java | 2 +- .../shatteredpixeldungeon/scenes/GameScene.java | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/BeaconOfReturning.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/BeaconOfReturning.java index 7a17a654f..ff02eed4a 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/BeaconOfReturning.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/spells/BeaconOfReturning.java @@ -131,7 +131,7 @@ public class BeaconOfReturning extends Spell { Char existing = Actor.findChar(returnPos); if (existing != null && existing != hero){ - Char toPush = !Char.hasProp(existing, Char.Property.IMMOVABLE) ? hero : existing; + Char toPush = Char.hasProp(existing, Char.Property.IMMOVABLE) ? hero : existing; ArrayList candidates = new ArrayList<>(); for (int n : PathFinder.NEIGHBOURS8) { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index b8c2dbe97..81511299f 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -527,7 +527,17 @@ public class GameScene extends PixelScene { new Flare( 5, 16 ).color( 0xFFFF00, true ).show( hero, 4f ) ; break; case RETURN: - ScrollOfTeleportation.appearVFX( Dungeon.hero ); + if (Dungeon.level.pit[Dungeon.hero.pos] && !Dungeon.hero.flying){ + //delay this so falling into the chasm processes properly + ShatteredPixelDungeon.runOnRenderThread(new Callback() { + @Override + public void call() { + ScrollOfTeleportation.appearVFX(Dungeon.hero); + } + }); + } else { + ScrollOfTeleportation.appearVFX(Dungeon.hero); + } break; case DESCEND: case FALL: From 4008adde84a45513b62cf0e486160cb7d559dda6 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Wed, 24 Sep 2025 16:30:15 -0400 Subject: [PATCH 48/62] v3.2.5: fixed cutout handling triggering when no cutout is there on iOS --- .../shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index 81511299f..15cdecacd 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -373,7 +373,7 @@ public class GameScene extends PixelScene { float menuBarMaxLeft = uiCamera.width-insets.right-MenuPane.WIDTH; int hpBarMaxWidth = 50; //default max width float buffBarTopRowMaxWidth = 55; //default max width - if (largeInsetTop == 0){ + if (largeInsetTop == 0 && insets.top > 0){ //iOS's Dynamic island badly obstructs the first buff bar row if (DeviceCompat.isiOS()){ //TODO bad to hardcode and approximate this atm From 594c364eec9961ff8a4151f7e4d238831ddb2784 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Wed, 24 Sep 2025 17:04:53 -0400 Subject: [PATCH 49/62] v3.2.5: golden bees can now be affected by aggression debuff --- .../shatteredpixeldungeon/actors/mobs/Bee.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bee.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bee.java index a36f8eb4b..a173228f2 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bee.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bee.java @@ -27,6 +27,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.AllyBuff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Amok; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; +import com.shatteredpixel.shatteredpixeldungeon.items.stones.StoneOfAggression; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.sprites.BeeSprite; import com.watabou.utils.Bundle; @@ -167,7 +168,9 @@ public class Bee extends Mob { && mob.alignment != Alignment.NEUTRAL && !mob.isInvulnerable(getClass()) && !(alignment == Alignment.ALLY && mob.alignment == Alignment.ALLY)) { - if (closest == null || Dungeon.level.distance(closest.pos, pos) > Dungeon.level.distance(mob.pos, pos)){ + //prefers char affected by aggression + if (closest == null || mob.buff(StoneOfAggression.Aggression.class) != null + || Dungeon.level.distance(closest.pos, pos) > Dungeon.level.distance(mob.pos, pos)){ closest = mob; } } From e56e2f6a27a93d3ffbdbb90967ca5fa66947675c Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Wed, 24 Sep 2025 17:04:58 -0400 Subject: [PATCH 50/62] v3.2.5: fixed effects like aggro not clearing from downed ghouls --- .../shatteredpixeldungeon/actors/mobs/Ghoul.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java index 387d3002c..7791a594e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java @@ -294,6 +294,9 @@ public class Ghoul extends Mob { Dungeon.level.occupyCell( ghoul ); ghoul.sprite.idle(); ghoul.sprite.showStatusWithIcon(CharSprite.POSITIVE, Integer.toString(Math.round(ghoul.HT/10f)), FloatingText.HEALING); + if (ghoul.enemy != null && ghoul.enemy.alignment == ghoul.alignment){ + ghoul.enemy = null; //reset enemy + } super.detach(); return true; } From 4f569dff7678fbc2b85833920428dd8a7863a3f2 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Wed, 24 Sep 2025 17:24:25 -0400 Subject: [PATCH 51/62] v3.2.5: DM-300's rock fall now deals damage (same as gnoll rockfall) --- .../shatteredpixeldungeon/actors/mobs/DM300.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DM300.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DM300.java index f49ec9f7a..487b3be84 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DM300.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/DM300.java @@ -682,10 +682,17 @@ public class DM300 extends Mob { @Override public void affectChar(Char ch) { - if (!(ch instanceof DM300)){ - Buff.prolong(ch, Paralysis.class, Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 5 : 3); - if (ch == Dungeon.hero) { - Statistics.bossScores[2] -= 100; + if (!(ch instanceof DM300 || ch instanceof Pylon)){ + if (Dungeon.isChallenged(Challenges.STRONGER_BOSSES)) { + ch.damage(Random.NormalIntRange(10, 20), this); + } else { + ch.damage(Random.NormalIntRange(6, 12), this); + } + if (ch.isAlive()) { + Buff.prolong(ch, Paralysis.class, Dungeon.isChallenged(Challenges.STRONGER_BOSSES) ? 5 : 3); + } else if (ch == Dungeon.hero){ + Dungeon.fail( target ); + GLog.n( Messages.get( GnollGeomancer.class, "rockfall_kill") ); } } } From 958bc5ecd00dd80a651a437e887092615deb4744 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Wed, 24 Sep 2025 18:00:14 -0400 Subject: [PATCH 52/62] v3.2.5: fixed pincushion merging keeping existing enchants, not incoming --- .../shatteredpixeldungeon/actors/buffs/PinCushion.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/PinCushion.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/PinCushion.java index dfed86573..6c5078aed 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/PinCushion.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/PinCushion.java @@ -38,10 +38,11 @@ public class PinCushion extends Buff { private ArrayList items = new ArrayList<>(); public void stick(MissileWeapon projectile){ - for (Item item : items){ - if (item.isSimilar(projectile)){ - item.merge(projectile); - if (TippedDart.lostDarts > 0){ + for (int i = 0; i < items.size(); i++) { + if (projectile.isSimilar(items.get(i))) { + projectile.merge(items.get(i)); + items.set(i, projectile); + if (TippedDart.lostDarts > 0) { Dart d = new Dart(); d.quantity(TippedDart.lostDarts); TippedDart.lostDarts = 0; From 093e7a6874d993b070d2522d6055a2578d2929d2 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 25 Sep 2025 10:35:16 -0400 Subject: [PATCH 53/62] v3.2.5: fixed crossbow charged shot melee not triggering in some cases --- .../shatteredpixeldungeon/items/weapon/melee/Crossbow.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Crossbow.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Crossbow.java index 208dd8e0d..99fcce464 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Crossbow.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/Crossbow.java @@ -22,12 +22,12 @@ package com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee; import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfBlastWave; -import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.darts.Dart; import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet; @@ -86,7 +86,10 @@ public class Crossbow extends MeleeWeapon { int dmg = super.proc(attacker, defender, damage); //stronger elastic effect - if (attacker.buff(ChargedShot.class) != null && !(curItem instanceof Dart)){ + if (attacker == Dungeon.hero + && Dungeon.hero.buff(ChargedShot.class) != null + //not proccing from a dart + && Dungeon.hero.belongings.attackingWeapon() == this){ //trace a ballistica to our target (which will also extend past them Ballistica trajectory = new Ballistica(attacker.pos, defender.pos, Ballistica.STOP_TARGET); //trim it to just be the part that goes past them From d88baaf36f733cd65659365edb0ce336224f0b22 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 25 Sep 2025 12:24:09 -0400 Subject: [PATCH 54/62] v3.2.5: updated translations and translator credits --- .../messages/actors/actors_cs.properties | 2 +- .../messages/actors/actors_pl.properties | 16 +++++----- .../messages/actors/actors_zh-hant.properties | 12 ++++---- .../messages/actors/actors_zh.properties | 2 +- .../assets/messages/items/items_cs.properties | 6 ++-- .../assets/messages/items/items_in.properties | 4 +-- .../assets/messages/items/items_ko.properties | 4 +-- .../assets/messages/items/items_nl.properties | 2 +- .../assets/messages/items/items_pl.properties | 26 ++++++++-------- .../assets/messages/items/items_vi.properties | 6 ++-- .../messages/items/items_zh-hant.properties | 30 +++++++++---------- .../messages/journal/journal_eo.properties | 2 +- .../messages/journal/journal_pl.properties | 10 +++---- .../messages/levels/levels_zh-hant.properties | 6 ++-- .../messages/levels/levels_zh.properties | 4 +-- .../assets/messages/misc/misc_vi.properties | 2 +- .../assets/messages/misc/misc_zh.properties | 6 ++-- .../messages/plants/plants_zh.properties | 8 ++--- .../messages/windows/windows_eo.properties | 2 +- .../messages/windows/windows_nl.properties | 4 +-- .../messages/windows/windows_pl.properties | 2 +- .../messages/Languages.java | 16 +++++----- 22 files changed, 86 insertions(+), 86 deletions(-) diff --git a/core/src/main/assets/messages/actors/actors_cs.properties b/core/src/main/assets/messages/actors/actors_cs.properties index 772662abb..f25643e67 100644 --- a/core/src/main/assets/messages/actors/actors_cs.properties +++ b/core/src/main/assets/messages/actors/actors_cs.properties @@ -668,7 +668,7 @@ actors.hero.spells.guidinglight.short_desc=Způsobí magické zranění na dálk actors.hero.spells.guidinglight.desc=Klerik sešle výboj magické energie, který zasáhne cíl, způsobí mu 2-8 poškození a osvětlí jej. Příští fyzický útok proti osvětlenému protivníkovi jej s jistotou zasáhne. actors.hero.spells.guidinglight.desc_priest=_Toto kouzlo je mocnější, když ho sesílá Kněz._ První seslání tohoto kouzla každých 50 tahů ho nestojí nabití, a způsobené osvětlení může být spotřebováno i hůlkami, útoky spojenců nebo artefakty, které přímo zacílí nepřátele. Tím způsobí bonusové poškození rovné úrovni Kněze +5. actors.hero.spells.guidinglight$guidinglightpriestcooldown.name=Naváděcí světlo -actors.hero.spells.guidinglight$guidinglightpriestcooldown.desc=The Priest will be able to cast Guiding Light for free again after 50 turns elapse.\n\nTurns remaining: %s. +actors.hero.spells.guidinglight$guidinglightpriestcooldown.desc=Kněz může znovu seslat Naváděcí světlo zadarmo po uplynutí 50 tahů.\n\nZbývá tahů: %s. actors.hero.spells.guidinglight$illuminated.name=Osvětlení actors.hero.spells.guidinglight$illuminated.desc=Tato postava je osvětlena zásahem naváděcího světla. Ačkoliv zář není dost jasná, aby osvětlila okolní terén, tento efekt pomůže Klerikovi zasadit ránu mnohem snáz. actors.hero.spells.guidinglight$illuminated.desc_priest=Kněz navíc může osvětlení spotřebovat pomocí záře, hůlek, artefaktů nebo útoků svých spojenců. Využití osvětlení tímto způsobem způsobí bonusové poškození ve výši úrovni Kněze +5. diff --git a/core/src/main/assets/messages/actors/actors_pl.properties b/core/src/main/assets/messages/actors/actors_pl.properties index c75cfa583..ae662d75d 100644 --- a/core/src/main/assets/messages/actors/actors_pl.properties +++ b/core/src/main/assets/messages/actors/actors_pl.properties @@ -497,7 +497,7 @@ actors.hero.abilities.rogue.deathmark.name=znak śmierci actors.hero.abilities.rogue.deathmark.ally_target=Możesz oznaczać tylko wrogów. actors.hero.abilities.rogue.deathmark.short_desc=Łotrzyk umieszcza _znak śmierci_ na wybranym wrogu. Naznaczeni przeciwnicy otrzymują bonusowe obrażenia, ale nie mogą umrzeć, dopóki znak nie zniknie. actors.hero.abilities.rogue.deathmark.desc=Łotrzyk umieszcza znak na wybranym wrogu, przez co ten otrzymuje dodatkowo 25% obrażeń. Znak jest nakładany natychmiastowo i znika po 5 turach.\n\nNaznaczeni przeciwnicy otrzymują bonusowe obrażenia, ale nie mogą umrzeć, dopóki znak nie zniknie. Jeśli wróg ma 0 PŻ, a znak przestanie działać, natychmiast zginie -actors.hero.abilities.rogue.deathmark$deathmarktracker.name=naznaczony znakiem śmierci +actors.hero.abilities.rogue.deathmark$deathmarktracker.name=naznaczenie znakiem śmierci actors.hero.abilities.rogue.deathmark$deathmarktracker.desc=Ten wróg został naznaczony, powodując że otrzyma 25%%dodatkowych obrażeń, ale także nie będzie mógł umrzeć, dopóki znak nie zniknie.\n\nPozostałe tury: %s. actors.hero.abilities.rogue.shadowclone.name=klon cienia actors.hero.abilities.rogue.shadowclone.short_desc=Łotrzyk przywołuje _klon cienia_, który może mu pomóc w walce. @@ -668,7 +668,7 @@ actors.hero.spells.guidinglight.short_desc=Zadaje obrażenia magiczne i gwarantu actors.hero.spells.guidinglight.desc=Kleryk wystrzeliwuje pocisk magicznej energii, który przy trafieniu w cel zadaje 2-8 obrażeń i go rozświetla. Następny atak fizyczny bronią, do której użycia masz wystarczającą siłę, przeciwko rozświetlonemu przeciwnikowi gwarantuje trafienie. actors.hero.spells.guidinglight.desc_priest=_To zaklęcie jest potężniejsze, gdy jest rzucane przez Kapłana._ Raz na 50 tur rzucenie zaklęcia nie kosztuje ładunków księgi, a efekt rozświetlenia będzie aktywowany przez blask, różdżki, inne postacie i artefakty, które bezpośrednio wpływają na przeciwników. Aktywowanie rozświetlenia w ten sposób zadaje dodatkowe magiczne obrażenia równe poziomowi Kapłana + 5. actors.hero.spells.guidinglight$guidinglightpriestcooldown.name=Światło Przewodnie -actors.hero.spells.guidinglight$guidinglightpriestcooldown.desc=Kapłan będzie mógł za darmo rzucić zaklęcie Światła Przewodniego, ponownie po upływie 50 tur.\n\nPozostałe tury: %s. +actors.hero.spells.guidinglight$guidinglightpriestcooldown.desc=Kapłan będzie mógł za darmo rzucić zaklęcie Światła Przewodniego ponownie po upływie 50 tur.\n\nPozostałe tury: %s. actors.hero.spells.guidinglight$illuminated.name=Rozświetlenie actors.hero.spells.guidinglight$illuminated.desc=Ta postać świeci w wyniku uderzenia przez zaklęcie światła przewodniego. Blask nie jest wystarczająco silny, aby rozjaśnić okolicę, natomiast ułatwi on Klerykowi trafienie tej postaci. actors.hero.spells.guidinglight$illuminated.desc_priest=Kapłan może dodatkowo aktywować rozświetlenie za pomocą blasku, różdżki, sojusznika lub efektami niektórych artefaktów. Aktywowanie rozświetlenia w ten sposób zada dodatkowe obrażenia magiczne równe poziomowi kapłana + 5. @@ -741,7 +741,7 @@ actors.hero.spells.radiance.desc=Kapłan wybucha świętym światłem, ogłuszaj actors.hero.spells.recallinscription.name=replikacja runy actors.hero.spells.recallinscription.short_desc=Powtarza ostatnio używany kamień runiczny lub zwój. -actors.hero.spells.recallinscription.desc=Kleryk używa świętej magii, aby ponownie rzucić efekt magicznej runy znalezionej na kamieniu runicznym lub zwoju, których użył w ostatnich %s turach.\n\nReplikacja Runy nie może być użyte do replikacji zwojów ulepszenia. Koszt ładowania tego zaklęcia różni się w zależności od tego, który przedmiot został ostatnio użyty: 2 za kamień runiczny, 3 za zwój, 4 za egzotyczny zwój. Koszt ładowania jest również podwajany podczas replikacji zwoju transmutacji lub przedmiotów alchemicznych, które muszą zostać wykonane za pomocą transmutacji lub ulepszenia. +actors.hero.spells.recallinscription.desc=Kleryk używa świętej magii, aby ponownie rzucić efekt magicznej runy ze zwoju lub kamienia runicznego, których użył w ostatnich %s turach.\n\nReplikacja Runy nie może być użyta do replikacji zwojów ulepszenia. Koszt ładunków księgi dla tego zaklęcia jest zależny od ostatnio użytego przedmiotu i wynosi 2 dla kamienia runicznego, 3 dla zwoju i 4 dla egzotycznego zwoju. Koszt jest dwukrotnie wyższy przy replikacji zwoju transmutacji lub przedmiotów tworzonych za pomocą zwoju transmutacji lub ulepszenia. actors.hero.spells.recallinscription$useditemtracker.name=niedawne użycie runy actors.hero.spells.recallinscription$useditemtracker.desc=Kleryk niedawno użył przedmiotu, który działa z zaklęciem Replikacji runy. Kleryk może rzucić zaklęcie, aby powtórzyć efekt przedmiotu.\n\nUżyty przedmiot: %1$s.\n\nPozostałe tury efektu: %2$s. @@ -893,7 +893,7 @@ actors.hero.talent$preciseassaulttracker.desc=Następny atak wręcz Fechmistrzyn actors.hero.talent$deadlyfollowuptracker.name=śmiertelna kontynuacja actors.hero.talent$deadlyfollowuptracker.desc=Fechmistrzyni niedawno zaatakowała przeciwnika bronią miotaną, dzięki czemu jej ataki wręcz przeciwko niemu będą zadawały dodatkowe obrażenia.\n\nPozostałe tury efektu: %s. actors.hero.talent$combinedlethalityabilitytracker.executed=zamordowany -actors.hero.talent$satiatedspellstracker.name=Zaklęcie Tarczy +actors.hero.talent$satiatedspellstracker.name=zaklęcie tarczy actors.hero.talent$satiatedspellstracker.desc=Następne zaklęcie rzucone przez Kleryka zapewni mu odrobinę osłony. actors.hero.talent$searinglightcooldown.name=Palące Światło actors.hero.talent$searinglightcooldown.desc=Niedawno użyłeś tego talentu i musisz poczekać, zanim użyjesz go ponownie.\n\nPozostałe tury: %s. @@ -1091,7 +1091,7 @@ actors.hero.talent.perfect_copy.desc=_+1:_ Cień zyskuje _10%_ maksymalnego zdro actors.hero.talent.natures_bounty.title=dar natury actors.hero.talent.natures_bounty.desc=_+1:_ Łowczyni może znaleźć _4 jagody_ ukryte w wysokiej trawie, gdy bada kilka następnych pięter lochu.\n\n_+2:_ Łowczyni może znaleźć _6 jagód_ ukrytych w wysokiej trawie, gdy bada kilka następnych pięter lochu.\n\nJagody je się stosunkowo szybko, jednak ciężko się nimi najeść, ale mogą zawierać one użyteczne nasiono. actors.hero.talent.survivalists_intuition.title=intuicja survivalistów -actors.hero.talent.survivalists_intuition.desc=_+1:_ Łowczyni identyfikuje bronie miotane _3x szybciej_.\n\n_+2:_ Łowczyni identyfikuje bronie miotane _gdy nimi trafi we wroga_. +actors.hero.talent.survivalists_intuition.desc=_+1:_ Łowczyni identyfikuje bronie miotane _3x szybciej_.\n\n_+2:_ Łowczyni identyfikuje bronie miotane, _gdy trafi nimi we wroga_. actors.hero.talent.followup_strike.title=uderzenie następujące actors.hero.talent.followup_strike.desc=_+1:_ Kiedy Łowczyni trafi przeciwnika swoim łukiem bądź za pomocą broni miotanej, jej kolejny atak wręcz przeciwko temu przeciwnikowi zada _2 dodatkowe obrażenia_.\n\n_+2:_ Kiedy Łowczyni trafi przeciwnika swoim łukiem bądź za pomocą broni miotanej, jej kolejny atak wręcz przeciwko temu przeciwnikowi zada _3 dodatkowe obrażenia_. actors.hero.talent.natures_aid.title=wsparcie natury @@ -1117,7 +1117,7 @@ actors.hero.talent.seer_shot.meta_desc=_Jeśli ten talent jest uzyskany przez in actors.hero.talent.farsight.title=Dalekowzroczność actors.hero.talent.farsight.desc=_+1:_ Pole widzenia Strzelczyni jest _powiększone o 25%_.\n\n_+2:_ Pole widzenia Strzelczyni jest _powiększone o 50%_.\n\n_+3:_ Pole widzenia Strzelczyni jest _powiększone o 75%_. actors.hero.talent.shared_enchantment.title=współdzielone zaklęcie -actors.hero.talent.shared_enchantment.desc=_+1:_ Bronie miotane posiadają _33% szans_ na użycie zaklęcia znajdującego się na łuku Strzelczyni.\n\n_+2:_ Bronie miotane posiadają _67% szans_ na użycie zaklęcia znajdującego się na łuku Strzelczyni.\n\n_+3:_ Bronie miotane posiadają _100% szans_ na użycie zaklęcia znajdującego się na łuku Strzelczyni.\n\nZaklęcie łuku może się aktywować razem z zaklęciem broni miotanej (jeżeli jakieś ma). +actors.hero.talent.shared_enchantment.desc=_+1:_ Bronie miotane mają _33% szans_ na użycie zaklęcia znajdującego się na łuku Strzelczyni.\n\n_+2:_ Bronie miotane mają _67% szans_ na użycie zaklęcia znajdującego się na łuku Strzelczyni.\n\n_+3:_ Bronie miotane mają _100% szans_ na użycie zaklęcia znajdującego się na łuku Strzelczyni.\n\nZaklęcie łuku może się aktywować razem z tym nałożonym na broń miotaną. actors.hero.talent.shared_upgrades.title=współdzielone ulepszenie actors.hero.talent.shared_upgrades.desc=_+1:_ Gdy Strzelczyni atakuje ulepszoną bronią miotaną, każdy jej poziom przedłuża czas działania naznaczenia o 1 turę i zwiększa obrażenia jej specjalnego ataku o 16%, na maksymalnie _2 tury i +33% obrażeń na poziomie +2_.\n\n_+2:_ Gdy Strzelczyni atakuje ulepszoną bronią miotaną, każdy jej poziom przedłuża czas działania naznaczenia o 1 turę i zwiększa obrażenia jej specjalnego ataku o 16%, na maksymalnie _4 tury i +67% obrażeń na poziomie +4_.\n\n_+3:_ Gdy Strzelczyni atakuje ulepszoną bronią miotaną, każdy jej poziom przedłuża czas działania naznaczenia o 1 turę i zwiększa obrażenia jej specjalnego ataku o 16%, na maksymalnie _6 tur i +100% obrażeń na poziomie +6_. @@ -1247,7 +1247,7 @@ actors.hero.talent.bless.desc=_+1:_ Kleryk może rzucić _błogosławieństwo_, actors.hero.talent.bless.meta_desc=_Jeśli ten talent jest uzyskany przez innego bohatera_, zwiększy on celność i unik bohatera oraz sojuszników o 3% przy +1 i 5% przy +2. actors.hero.talent.cleanse.title=Oczyszczenie -actors.hero.talent.cleanse.desc=_+1:_ Kleryk może rzucić _Oczyszczenie_, kosztujące 2 ładunki, które jest czarem, _usuwającym negatywne efekty_ nałożone na Kleryka i pobliskich sojuszników oraz dając im też _10 osłony_.\n\n_+2:_ Kleryk może rzucić _Oczyszczenie_, kosztujące 2 ładunki, które jest czarem, _dającym 3 tury odporności na negatywne efekty_ Klerykowi i pobliskim sojusznikom oraz dając im też _20 osłony_.\n\n_+3:_ Kleryk może rzucić _Oczyszczenie_, kosztujące 2 ładunki, które jest czarem, _dającym 5 tur odporności na negatywne efekty_ Klerykowi i pobliskim sojusznikom oraz dając im też _30 osłony_. +actors.hero.talent.cleanse.desc=_+1:_ Kleryk może rzucić _oczyszczenie_, czar kosztujący 2 ładunki, który _usuwa negatywne efekty_ nałożone na Kleryka i pobliskich sojuszników oraz daje im _10 osłony_.\n\n_+2:_ Kleryk może rzucić _oczyszczenie_, czar kosztujący 2 ładunki, który daje Klerykowi i pobliskim sojusznikom _3 tury odporności na negatywne efekty_ oraz _20 osłony_.\n\n_+3:_ Kleryk może rzucić _oczyszczenie_, czar kosztujący 2 ładunki, który daje Klerykowi i pobliskim sojusznikom _5 tur odporności na negatywne efekty_ oraz _30 osłony_. actors.hero.talent.cleanse.meta_desc=_Jeśli ten talent jest uzyskany przez innego bohatera_, zapewnia on 10/20/30% szansy przy +1/+2/+3 na oczyszczenie bohatera z negatywnych efektów po użyciu różdżki lub artefaktu. actors.hero.talent.light_reading.title=Rzut Okiem actors.hero.talent.light_reading.desc=_+1:_ Kleryk może używać świętej księgi, gdy nie jest założona, ale wtedy ładuje się ona z _25% prędkości_.\n\n_+2:_ Kleryk może używać świętej księgi, gdy nie jest założona, ale wtedy ładuje się ona z _50% prędkości_.\n\n_+3:_ Kleryk może używać świętej księgi, gdy nie jest założona, ale wtedy ładuje się ona z _75% prędkości_. @@ -1270,7 +1270,7 @@ actors.hero.talent.wall_of_light.desc=_+1:_ Paladyn może rzucić _Ścianę Świ actors.hero.talent.divine_intervention.title=boska interwencja actors.hero.talent.divine_intervention.desc=_+1:_ Będąc w Niebiańskiej Postaci, Kleryk może rzucić _Boską Interwencję_, która zapewnia Klerykowi i wszystkim sojusznikom do _150 punktów tarczy_ oraz wydłuża Niebiańską Postać o _3 tury_.\n\n_+2:_ Będąc w Niebiańskiej Postaci, Kleryk może rzucić _Boską Interwencję_, która zapewnia Klerykowi i wszystkim sojusznikom do _200 punktów tarczy_ oraz wydłuża Niebiańską Postać o _4 tury_.\n\n_+3:_ Będąc w Niebiańskiej Postaci, Kleryk może rzucić _Boską Interwencję_, która zapewnia Klerykowi i wszystkim sojusznikom do _250 punktów tarczy_ oraz wydłuża Niebiańską Postać o _5 tur_.\n\n_+4:_ Będąc w Niebiańskiej Postaci, Kleryk może rzucić _Boską Interwencję_, która zapewnia Klerykowi i wszystkim sojusznikom do _300 punktów tarczy_ oraz wydłuża Niebiańską Postać o _6 tur_.\n\nBoska Interwencja kosztuje aż 5 ładunków księgi i może być rzucona tylko raz w danej Niebiańskiej Postaci. actors.hero.talent.judgement.title=osąd -actors.hero.talent.judgement.desc=_+1:_ Będąc w niebiańskiej formie, Kleryk może rzucić _osąd_, który zadaje _10-20 obrażeń_ wszystkim widocznym wrogom.\n\n_+2:_ Będąc w niebiańskiej formie, Kleryk może rzucić _osąd_, który zadaje _15-30 obrażeń_ wszystkim widocznym wrogom.\n\n_+3:_ Będąc w niebiańskiej formie, Kleryk może rzucić _osąd_, który zadaje _20-40 obrażeń_ wszystkim widocznym wrogom.\n\n_+4:_ Będąc w niebiańskiej formie, Kleryk może rzucić _osąd_, który zadaje _25-50 obrażeń_ wszystkim widocznym wrogom.\n\nOsąd kosztuje 3 ładunki tomu. Zadaje on +33% obrażeń za każde zaklęcie rzucone przez Kleryka od momentu wejścia w formę lub od ostatniego rzucenia osądu. +actors.hero.talent.judgement.desc=_+1:_ Będąc w niebiańskiej formie, Kleryk może rzucić _osąd_, który zadaje _10-20 obrażeń_ wszystkim widocznym wrogom.\n\n_+2:_ Będąc w niebiańskiej formie, Kleryk może rzucić _osąd_, który zadaje _15-30 obrażeń_ wszystkim widocznym wrogom.\n\n_+3:_ Będąc w niebiańskiej formie, Kleryk może rzucić _osąd_, który zadaje _20-40 obrażeń_ wszystkim widocznym wrogom.\n\n_+4:_ Będąc w niebiańskiej formie, Kleryk może rzucić _osąd_, który zadaje _25-50 obrażeń_ wszystkim widocznym wrogom.\n\nOsąd kosztuje 3 ładunki księgi. Zadaje on +33% obrażeń za każde zaklęcie rzucone przez Kleryka od momentu wejścia w formę lub od ostatniego rzucenia osądu. actors.hero.talent.flash.title=błysk actors.hero.talent.flash.desc=_+1:_ Będąc w niebiańskiej formie, Kleryk może rzucić _błysk_, aby teleportować się na odległość do _3 pól_.\n\n_+2:_ Będąc w niebiańskiej formie, Kleryk może rzucić _błysk_, aby teleportować się na odległość do _4 pól_.\n\n_+3:_ Będąc w niebiańskiej formie, Kleryk może rzucić _błysk_, aby teleportować się na odległość do _5 pól_.\n\n_+4:_ Będąc w niebiańskiej formie, Kleryk może rzucić _błysk_, aby teleportować się na odległość do _6 pól_.\n\nBłysk kosztuje początkowo 2 ładunki tomu i 1 dodatkowy ładunek za każde użycie w tej samej niebiańskiej formie. diff --git a/core/src/main/assets/messages/actors/actors_zh-hant.properties b/core/src/main/assets/messages/actors/actors_zh-hant.properties index 0057541e4..5c1752372 100644 --- a/core/src/main/assets/messages/actors/actors_zh-hant.properties +++ b/core/src/main/assets/messages/actors/actors_zh-hant.properties @@ -122,14 +122,14 @@ actors.buffs.bleeding.name=流血 actors.buffs.bleeding.ondeath=你因失血過多而死…… actors.buffs.bleeding.heromsg=你正在流血! actors.buffs.bleeding.rankings_desc=流血至死 -actors.buffs.bleeding.desc=這傷口正湧出大量血液,令人十分不安。 \n\n流血時每回合都會造成傷害。這種傷害值每回合都會隨機減少,直到出血停止為止。 \n\n目前流血傷害:%d。 +actors.buffs.bleeding.desc=這傷口正湧出大量血液,令人十分不安。 \n\n流血時每回合都會造成傷害。這種傷害值每回合都可能隨機減少,直到出血停止為止。 \n\n目前流血傷害:%d。 actors.buffs.bless.name=祝福 actors.buffs.bless.desc=你的集中力正在噴薄而出,有人說這是神賜的禮物。\n\n祝福狀態能夠提高自己25%%的命中率與閃避率,使被祝福者在戰鬥中勢如破竹。\n\n祝福效果剩餘:%s回合 actors.buffs.blindness.name=失明 actors.buffs.blindness.heromsg=你失明了! -actors.buffs.blindness.desc=失明使週遭陷入一片黑暗。 \n\n失明的單位的可視範圍被限制在一格以內、使遠程攻擊變得毫無作用、同時也很容易跟丟敵人。此外,英雄失明時無法閱讀書本或是卷軸。 \n失明效果剩餘:%s回合 +actors.buffs.blindness.desc=失明使週遭陷入一片黑暗。 \n\n失明的單位的可視範圍被限制在一格以內、使遠程攻擊變得毫無作用、同時也很容易跟丟敵人。此外,英雄失明時無法閱讀書本或是卷軸。 \n\n失明效果剩餘:%s回合 actors.buffs.buff.heromsg= @@ -186,7 +186,7 @@ actors.buffs.combo$combomove.fury.desc=攻擊一名敵人數次,攻擊次數 actors.buffs.combo$combomove.fury.empower_desc=_前躍最多%d格以靠近敵人_並攻擊其數次,攻擊次數等同於連擊數。每次攻擊造成60%%傷害,並可以觸發武器附魔效果。使用後重置連擊數。 actors.buffs.corruption.name=腐化 -actors.buffs.corruption.desc=腐化魔法能滲透至生物的本質,扭曲其原本的意志。\n\n被腐化的生物會攻擊友方,忽略原有的敵人。腐化魔法也會傷害生物,讓他們緩慢走向死亡。\n\n腐化是永久性的,唯有死亡才能獲得解脫。 +actors.buffs.corruption.desc=腐化魔法能滲透至生物的本質,扭曲其原本的意志。\n\n被腐化的生物會攻擊友方,忽略原有的敵人。腐化魔法也會傷害生物,讓他們緩慢走向死亡。\n\n遭腐化後就無法脫身,唯有死亡才能獲得解脫。 actors.buffs.cripple.name=殘廢 actors.buffs.cripple.heromsg=你殘廢了! @@ -201,7 +201,7 @@ actors.buffs.degrade.heromsg=你的裝備被暫時弱化了! actors.buffs.degrade.desc=強大的黑暗魔法正在吞噬升級卷軸注入你裝備的魔力!\n\n降級狀態下的裝備會被視作比起原有等級更低的狀態。_超過3級以後的每一級都會受到更嚴重的削弱_。物品的描述也會根據降級的影響而改變。\n\n不過,降級不會影響裝備的力量需求,法杖充能,投擲武器耐久,以及神器。\n\n降級效果剩餘:%s回合。使用一張升級卷軸或祛邪卷軸可以立即驅散這種黑暗魔法。 actors.buffs.doom.name=定命 -actors.buffs.doom.desc=當整個世界都看起來想置你於死地時,繼續鬥爭還有什麼意義呢?\n\n被定命的單位受到的任何傷害都會提升67% 。\n\n定命是永久性的,唯有死亡才能獲得解脫。 +actors.buffs.doom.desc=當整個世界都看起來想置你於死地時,繼續鬥爭還有什麼意義呢?\n\n被定命的單位受到的任何傷害都會提升67% 。\n\n遭定命後就無法脫身,唯有死亡才能獲得解脫。 actors.buffs.dread.name=魂飛魄散 actors.buffs.dread.desc=目標已被嚇至魂飛魄散,正在極度的恐慌下嘗試逃出這座地下城!\n\n魂飛魄散的生物將快速逃離它們的敵人,並且會在離開敵人可視範圍後立即消失在整座地下城中。逃離的敵人不會掉落道具,只會給予玩家減半的經驗值獎勵。傷害所造成的痛楚將促使其鎮定下來。\n\n魂飛魄散效果剩餘時長:%d 回合。 @@ -1292,7 +1292,7 @@ actors.hero.talent.stasis.desc=習得法術_星界投射_,可耗2點充能暫 #universal actors.hero.talent.heroic_energy.title=英氣威能 actors.hero.talent.heroic_energy.rat_title=鼠氣威能 -actors.hero.talent.heroic_energy.desc=_+1:_英雄護甲的充能消耗量_減少至原先的12%_。\n\n_+2:_英雄護甲的充能消耗量_減少至原先的23%_。\n\n_+3:_英雄護甲的充能消耗量_減少至原先的32%_。\n\n_+4:_英雄護甲的充能消耗量_減少至原先的40%_。 +actors.hero.talent.heroic_energy.desc=_+1:_英雄護甲的充能消耗量_減少12%_。\n\n_+2:_英雄護甲的充能消耗量_減少23%_。\n\n_+3:_英雄護甲的充能消耗量_減少32%_。\n\n_+4:_英雄護甲的充能消耗量_減少40%_。 actors.hero.talent.ratsistance.title=鼠族抗性 actors.hero.talent.ratsistance.desc=_+1:_鼠化敵人傷害為原先的_90%_。\n\n_+2:_鼠化敵人傷害為原先的_81%_。\n\n_+3:_鼠化敵人傷害為原先的_73%_。\n\n_+4:_鼠化敵人傷害為原先的_65%_。 @@ -1378,7 +1378,7 @@ actors.mobs.npcs.prismaticimage.discover_hint=此盟友為閱讀某種卷軸後 actors.mobs.npcs.ratking.name=鼠王 actors.mobs.npcs.ratking.not_sleeping=我可不是在睡覺! -actors.mobs.npcs.ratking.what_is_it=那傢伙是甚麼鬼?我可沒時間管這些破事。我的王國可不會自己運轉下去! +actors.mobs.npcs.ratking.what_is_it=現在又怎麼了?我可沒時間管這些破事。我的王國可不會自己運轉下去! actors.mobs.npcs.ratking.confused=這……我這是在哪? 我的王國需要我! actors.mobs.npcs.ratking.crown_clothes=把衣服穿上!我可不會批准你與我會面! actors.mobs.npcs.ratking.crown_desc=哇喔!那王冠是給我的嗎?那看起來比我的閃亮多了,那我就好心好意的收下了!\n\n我正在想我能給你點獎賞……一種使你如同英雄的強大能力如何? diff --git a/core/src/main/assets/messages/actors/actors_zh.properties b/core/src/main/assets/messages/actors/actors_zh.properties index 046ecadb5..b90ee392d 100644 --- a/core/src/main/assets/messages/actors/actors_zh.properties +++ b/core/src/main/assets/messages/actors/actors_zh.properties @@ -1119,7 +1119,7 @@ actors.hero.talent.farsight.desc=_+1:_狙击手的视野范围_扩大25%_。\n actors.hero.talent.shared_enchantment.title=联动附魔 actors.hero.talent.shared_enchantment.desc=_+1:_投掷武器_有33%概率_附带狙击手灵能弓上的附魔。\n\n_+2:_投掷武器_有67%概率_附带狙击手灵能弓上的附魔。\n\n_+3:_投掷武器_有100%概率_附带狙击手灵能弓上的附魔。\n\n无论投掷武器附有哪种附魔,均能正常触发灵能弓的附魔。 actors.hero.talent.shared_upgrades.title=联动升级 -actors.hero.talent.shared_upgrades.desc=当狙击手以一件已升级的投掷武器攻击时,其每级升级都会延长1回合狙击标记持续时间并增加16%特殊攻击伤害。\n\n_+1:_狙击手的投掷武器最多提供_2级_加成,可最多延长_2回合_狙击标记持续时间并增加_33%_特殊攻击伤害。\n\n_+2:_狙击手的投掷武器最多提供_4级_加成,可最多延长_4回合_狙击标记持续时间并增加_67%_特殊攻击伤害。\n\n_+3:_狙击手的投掷武器最多提供_6级_加成,可最多延长_6回合_狙击标记持续时间并增加_100%_特殊攻击伤害。 +actors.hero.talent.shared_upgrades.desc=当狙击手以一件已升级的投掷武器攻击时,其每级升级都会延长1回合狙击标记持续时间并增加16%特殊攻击伤害。\n\n_+1:_狙击手的投掷武器被限制为最多提供_2级_加成,以延长_2回合_狙击标记持续时间并增加_33%_特殊攻击伤害。\n\n_+2:_狙击手的投掷武器被限制为最多提供_4级_加成,以延长_4回合_狙击标记持续时间并增加_67%_特殊攻击伤害。\n\n_+3:_狙击手的投掷武器被限制为最多提供_6级_加成,以延长_6回合_狙击标记持续时间并增加_100%_特殊攻击伤害。 actors.hero.talent.durable_tips.title=持久药液 actors.hero.talent.durable_tips.desc=_+1:_守望者的涂药飞镖拥有_2倍耐久_。\n\n_+2:_守望者的涂药飞镖拥有_3倍耐久_。\n\n_+3:_守望者的涂药飞镖拥有_4倍耐久_。 diff --git a/core/src/main/assets/messages/items/items_cs.properties b/core/src/main/assets/messages/items/items_cs.properties index 4d9983e3c..5df12c6e1 100644 --- a/core/src/main/assets/messages/items/items_cs.properties +++ b/core/src/main/assets/messages/items/items_cs.properties @@ -2201,11 +2201,11 @@ items.weapon.missiles.shuriken$shurikeninstanttracker.name=Cooldown shurikenu items.weapon.missiles.shuriken$shurikeninstanttracker.desc=Nedávno jsi hodil shuriken okamžitě, a musíš počkat, než to bueš moct provést znovu. Shurikeny můžeš stále používat, ale s normální rychlostí útoku.\n\nZbývá tahů: %s. items.weapon.missiles.throwingclub.name=Vrhací palice -items.weapon.missiles.throwingclub.stats_desc= +items.weapon.missiles.throwingclub.stats_desc=Tato zbraň se nezabodává do nepřátel a může být inhned sebrána. items.weapon.missiles.throwingclub.desc=Poměrně jednoduchá a pevná vrhací zbraň, v podstatě velký kámen připevněný k tyči. items.weapon.missiles.throwinghammer.name=Vrhací kladivo -items.weapon.missiles.throwinghammer.stats_desc= +items.weapon.missiles.throwinghammer.stats_desc=Tato zbraň se nezabodává do nepřátel a může být inhned sebrána. items.weapon.missiles.throwinghammer.desc=Tyto robustní kladiva jsou navržena pro házení po nepřátelích. Jejich hladká celokovová konstrukce jim propůjčuje značnou výdrž. items.weapon.missiles.throwingknife.name=Vrhací nůž @@ -2236,7 +2236,7 @@ items.weapon.spiritbow.name=Přízračný luk items.weapon.spiritbow.ac_shoot=STŘELIT items.weapon.spiritbow.prompt=Vyber cíl items.weapon.spiritbow.stats=Luk nemůže být přímo vylepšován, ale místo toho se stává postupně silnější s tvou úrovní. Šípy vystřelené z luku způsobí na tvé současné úrovni _%1$d-%2$d poškození_ a samotný luk vyžaduje _%3$d bodů síly_ pro řádné využití. -items.weapon.spiritbow.desc=Luk vytvořený z prastarého magického dřeva. Struna luku a jeho ornamenty září bledě modrým světlem. Když je struna napnuta, vykouzlí luk magický šíp, který může být vypálen po nepříteli. +items.weapon.spiritbow.desc=Luk vytvořený z prastarého magického dřeva. Tětiva luku a jeho ornamenty září bledě modrým světlem. Když je tětiva napnuta, vykouzlí luk magický šíp, který může být vypálen po nepříteli. items.weapon.spiritbow.discover_hint=S tímto předmětem začíná jeden z hrdinů. items.weapon.weapon.identify=Nyní dostatečně znáš svou zbraň. diff --git a/core/src/main/assets/messages/items/items_in.properties b/core/src/main/assets/messages/items/items_in.properties index 697332cc5..fa12fdb14 100644 --- a/core/src/main/assets/messages/items/items_in.properties +++ b/core/src/main/assets/messages/items/items_in.properties @@ -2201,11 +2201,11 @@ items.weapon.missiles.shuriken$shurikeninstanttracker.name=cooldown shuriken items.weapon.missiles.shuriken$shurikeninstanttracker.desc=Kamu baru saja melempar shuriken secara instan, dan harus menunggu sebelum melakukannya lagi. Shuriken masih bisa dilempar, tetapi dengan kecepatan senjata normal.\n\nGiliran Tersisa: %s. items.weapon.missiles.throwingclub.name=palu lempar kecil -items.weapon.missiles.throwingclub.stats_desc= +items.weapon.missiles.throwingclub.stats_desc=Senjata ini tidak menempel pada musuh dan bisa diambil secara instan. items.weapon.missiles.throwingclub.desc=Senjata lempar yang cukup sederhana tetapi tahan lama, pada dasarnya berupa batu besar yang diikatkan pada tongkat. items.weapon.missiles.throwinghammer.name=palu lempar -items.weapon.missiles.throwinghammer.stats_desc= +items.weapon.missiles.throwinghammer.stats_desc=Senjata ini tidak menempel pada musuh dan bisa diambil secara instan. items.weapon.missiles.throwinghammer.desc=Palu-palu berat ini dirancang untuk dilempar ke arah musuh. Konstruksi logamnya yang halus membuatnya cukup tahan lama. items.weapon.missiles.throwingknife.name=pisau lempar diff --git a/core/src/main/assets/messages/items/items_ko.properties b/core/src/main/assets/messages/items/items_ko.properties index f46b83542..6e95e0322 100644 --- a/core/src/main/assets/messages/items/items_ko.properties +++ b/core/src/main/assets/messages/items/items_ko.properties @@ -2201,11 +2201,11 @@ items.weapon.missiles.shuriken$shurikeninstanttracker.name=재사용 대기 시 items.weapon.missiles.shuriken$shurikeninstanttracker.desc=당신은 최근에 수리검을 턴 소모 없이 던졌으며, 다시 그렇게 하기 위해서는 기다려야만 합니다. 수리검은 여전히 던질 수 있지만, 일반적인 공격 속도를 가질 것입니다.\n\n남은 턴: %s. items.weapon.missiles.throwingclub.name=투척용 몽둥이 -items.weapon.missiles.throwingclub.stats_desc= +items.weapon.missiles.throwingclub.stats_desc=이 무기는 적에게 고정되지 않아 적중 후 빠르게 다시 주워 사용할 수 있습니다. items.weapon.missiles.throwingclub.desc=매우 단순하지만 내구성이 뛰어난 투척 무기로, 기본적으로 막대기에 큰 돌을 고정한 형태입니다. items.weapon.missiles.throwinghammer.name=투척용 망치 -items.weapon.missiles.throwinghammer.stats_desc= +items.weapon.missiles.throwinghammer.stats_desc=이 무기는 적에게 고정되지 않아 적중 후 빠르게 다시 주워 사용할 수 있습니다. items.weapon.missiles.throwinghammer.desc=이 묵직한 망치는 적에게 던지기 위해 만들어졌습니다. 튼튼하고 매끈한 무쇠로 만들어져 내구성이 높습니다. items.weapon.missiles.throwingknife.name=투척용 칼 diff --git a/core/src/main/assets/messages/items/items_nl.properties b/core/src/main/assets/messages/items/items_nl.properties index a425b6fab..bb35df585 100644 --- a/core/src/main/assets/messages/items/items_nl.properties +++ b/core/src/main/assets/messages/items/items_nl.properties @@ -2184,7 +2184,7 @@ items.weapon.missiles.missileweapon.distance=Werpwapens zijn nauwkeuriger op afs items.weapon.missiles.missileweapon.durability=Werpwapens slijten en breken als ze worden gebruikt. items.weapon.missiles.missileweapon.uses_left=Deze set van werpwapens kan nog _%d/%d_ keer worden gebruikt voordat er één breekt. items.weapon.missiles.missileweapon.unlimited_uses=De kwaliteit van deze set is zo hoog dat hij vrijwel eeuwig meegaat. -items.weapon.missiles.missileweapon.unknown_uses=Normaal gesproken kun je deze set werpwapens _%d_ gebruiken voordat er één kapotgaat. +items.weapon.missiles.missileweapon.unknown_uses=Normaal gesproken kun je deze set werpwapens _%d_ keer gebruiken voordat er één kapotgaat. items.weapon.missiles.missileweapon.curse_discover=Dit werwapen is vervloekt! items.weapon.missiles.missileweapon.about_to_break=Je werpwapen staat op het punt te breken. items.weapon.missiles.missileweapon.has_broken=Eén van je werpwapens is kapot. diff --git a/core/src/main/assets/messages/items/items_pl.properties b/core/src/main/assets/messages/items/items_pl.properties index 56186aa83..f0c5fae7d 100644 --- a/core/src/main/assets/messages/items/items_pl.properties +++ b/core/src/main/assets/messages/items/items_pl.properties @@ -1462,7 +1462,7 @@ items.trinkets.shardofoblivion.identify_not_yet=Ten przedmiot nie jest jeszcze g items.trinkets.shardofoblivion.identify=Zidentyfikowano przedmiot! items.trinkets.shardofoblivion$wandusetracker.name=Użycie Niezidentyfikowanej Różdżki items.trinkets.shardofoblivion$wandusetracker.desc=Niedawno została użyta niezidentyfikowana różdżka, która na potrzeby złota głupców tymczasowo liczy się jako niezidentyfikowany element ekwipunku.\n\nPozostałe tury efektu: %s. -items.trinkets.shardofoblivion$thrownusetracker.name=Użycie Niezidentyfikowanej Broni Miotanej +items.trinkets.shardofoblivion$thrownusetracker.name=użycie niezidentyfikowanej broni miotanej items.trinkets.shardofoblivion$thrownusetracker.desc=Niedawno została użyta niezidentyfikowana broń miotana, która na potrzeby złota głupców tymczasowo liczy się jako niezidentyfikowany element ekwipunku.\n\nPozostałe tury efektu: %s. items.trinkets.thirteenleafclover.name=trzynastolistna koniczyna @@ -2166,7 +2166,7 @@ items.weapon.missiles.forcecube.stats_desc=Ta broń po rzuceniu rozkłada impakt items.weapon.missiles.forcecube.desc=Te magiczne kostki o osobliwym kształcie są wystarczająco małe, aby dało się je trzymać w dłoni, ale mimo tego są bardzo ciężkie. items.weapon.missiles.heavyboomerang.name=ciężki bumerang -items.weapon.missiles.heavyboomerang.stats_desc=Ta broń wraca do miejsca, z którego została rzucona po kilku turach. +items.weapon.missiles.heavyboomerang.stats_desc=Po kilku turach, ta broń wraca w miejsce, z którego została rzucona. items.weapon.missiles.heavyboomerang.desc=Ten wielki bumerang wymaga wprawy, ale zadaje znaczne obrażenia. items.weapon.missiles.javelin.name=oszczep @@ -2195,29 +2195,29 @@ items.weapon.missiles.missileweapon.break_upgraded_warn_no=Nie items.weapon.missiles.missileweapon$placeholder.name=broń miotana items.weapon.missiles.shuriken.name=shuriken -items.weapon.missiles.shuriken.stats_desc=Shurikeny można rzucać natychmiast co 20 tur. +items.weapon.missiles.shuriken.stats_desc=Shurikeny można rzucać natychmiastowo raz na 20 tur. items.weapon.missiles.shuriken.desc=Te gwiaździste kawałki metalu z ostrymi jak brzytwa krawędziami są lekkie i proste do użycia w trakcie ruchu. -items.weapon.missiles.shuriken$shurikeninstanttracker.name=Odnowienie Shurikena -items.weapon.missiles.shuriken$shurikeninstanttracker.desc=Niedawno został rzucony shuriken bez wykorzystania tury, musisz poczekać zanim możesz zrobić to ponownie. Dalej można rzucać shurikenami z normalną prędkością ataku.\n\nPozostało tur: %s. +items.weapon.missiles.shuriken$shurikeninstanttracker.name=odnowienie shurikena +items.weapon.missiles.shuriken$shurikeninstanttracker.desc=Niedawno wykonany rzut shurikenem był natychmiastowy, musisz poczekać, zanim zrobisz to ponownie. Shurikenami wciąż można rzucać z normalną prędkością ataku.\n\nPozostałe tury: %s. items.weapon.missiles.throwingclub.name=maczuga do rzucania -items.weapon.missiles.throwingclub.stats_desc=Ta broń nie pozostaje przy przeciwnikach i można ją od razu podnieść. +items.weapon.missiles.throwingclub.stats_desc=Ta broń nie wbija się w przeciwników i można ją natychmiastowo podnieść. items.weapon.missiles.throwingclub.desc=Całkiem prosta broń miotana; w zasadzie jest to wielki kamień przywiązany do patyka. items.weapon.missiles.throwinghammer.name=młot do rzucania -items.weapon.missiles.throwinghammer.stats_desc=Ta broń nie pozostaje przy przeciwnikach i można ją od razu podnieść. -items.weapon.missiles.throwinghammer.desc=Te ciężkie młoty zostały zaprojektowane do rzucania we wrogów. Ich konstrukcja z metalu powoduje że są wytrzymałe. +items.weapon.missiles.throwinghammer.stats_desc=Ta broń nie wbija się w przeciwników i można ją natychmiastowo podnieść. +items.weapon.missiles.throwinghammer.desc=Te ciężkie młoty zostały zaprojektowane do rzucania we wrogów. Są odlane w całości z metalu, co czyni je wytrzymałymi. items.weapon.missiles.throwingknife.name=nóż do rzucania items.weapon.missiles.throwingknife.stats_desc=Ta broń jest mocniejsza wobec nieświadomych niczego wrogów. -items.weapon.missiles.throwingknife.desc=Te lekkie noże są wyważone tak, aby, lecąc po łuku, trafiały prosto w cel. +items.weapon.missiles.throwingknife.desc=Te lekkie noże są wyważone tak, aby leciały po łuku, trafiając prosto w cel. items.weapon.missiles.throwingknife.discover_hint=Z tym przedmiotem zaczyna jeden z bohaterów. items.weapon.missiles.throwingspear.name=włócznia do rzucania -items.weapon.missiles.throwingspear.desc=Te lekkie włócznie mają cienką konstrukcję, która została zaprojektowane z myślą o rzucaniu, nie o walce wręcz. +items.weapon.missiles.throwingspear.desc=Te lekkie włócznie mają cienką konstrukcję, zaprojektowaną z myślą o rzucaniu, nie o walce wręcz. items.weapon.missiles.throwingspike.name=kolec do rzucania -items.weapon.missiles.throwingspike.desc=Te naostrzone kawałki metalu są przeznaczone do rażenia nimi odległych przeciwników. +items.weapon.missiles.throwingspike.desc=Te wytrzymałe, spiczaste kawałki metalu służą do rzucania nimi w oddalonych przeciwników. items.weapon.missiles.throwingspike.discover_hint=Z tym przedmiotem zaczyna jeden z bohaterów. items.weapon.missiles.throwingstone.name=kamień do rzucania @@ -2225,7 +2225,7 @@ items.weapon.missiles.throwingstone.desc=Te kamienie są piaskowane, aby można items.weapon.missiles.throwingstone.discover_hint=Z tym przedmiotem zaczyna jeden z bohaterów. items.weapon.missiles.tomahawk.name=tomahawk -items.weapon.missiles.tomahawk.stats_desc=Ta broń wykrwawi przeciwnika o połowę zadanych mu obrażeń. +items.weapon.missiles.tomahawk.stats_desc=Ta broń powoduje krwawienie u przeciwnika w wysokości połowy zadanych mu obrażeń. items.weapon.missiles.tomahawk.desc=Te siekiery do rzucania posiadają ząbkowane ostrza, rozrywające skórę po wbiciu się w przeciwnika. items.weapon.missiles.trident.name=trójząb @@ -2305,7 +2305,7 @@ items.dewdrop.name=kropla rosy items.dewdrop.already_full=Jesteś już w pełni sił. items.dewdrop.desc=Kryształowo czysta kropla rosy.\n\nDzięki magii tego miejsca czysta woda ma pewne właściwości lecznicze. -items.equipableitem.curse_detected=Wyczuwasz że przedmiot jest przeklęty tuż przed jego założeniem! +items.equipableitem.curse_detected=Tuż przed założeniem przedmiotu wyczuwasz, że jest on przeklęty! items.equipableitem.unequip_cursed=Nie możesz zdjąć przeklętego przedmiotu! items.equipableitem.ac_equip=ZAŁÓŻ items.equipableitem.ac_unequip=ZDEJMIJ diff --git a/core/src/main/assets/messages/items/items_vi.properties b/core/src/main/assets/messages/items/items_vi.properties index 5fde80ef7..341291e2c 100644 --- a/core/src/main/assets/messages/items/items_vi.properties +++ b/core/src/main/assets/messages/items/items_vi.properties @@ -1034,11 +1034,11 @@ items.rings.ringofforce$brawlersstance.name=thế đứng chiến binh items.rings.ringofforce$brawlersstance.desc=Khi đang ở trong thế đứng này, các đòn tấn công thông thường của Kiếm sĩ sẽ sử dụng một chiếc nhẫn lực đánh đã được trang bị kể cả khi cô ấy có trang bị một vũ khí. Những đòn tấn công này được tăng sát thương và sẽ vẫn sử dụng cường hóa và phù phép của món vũ khí.\n\nTuy vậy, duy trì thế đứng này cần sự tập trung, làm giảm tốc độ hồi năng vũ khí đi 50%.\n\nThế đứng này có thể được bật hoặc tắt bằng cách sử dụng một chiếc nhẫn lực đánh, nhưng sự giảm tốc độ hồi năng sẽ còn tồn tại trong một thời gian ngắn nếu thế đứng được kích hoạt và hủy nhanh chóng. items.rings.ringoffuror.name=nhẫn căm giận -items.rings.ringoffuror.stats=Khi được đeo, chiếc nhẫn này sẽ tăng tốc độ các đòn tấn công của bạn thêm _%s%%._ +items.rings.ringoffuror.stats=Khi được đeo, chiếc nhẫn này sẽ tăng tốc độ của các đòn tấn công của bạn thêm _%s%%._ items.rings.ringoffuror.typical_stats=Khi được đeo, chiếc nhẫn này thông thường sẽ tăng tốc độ các đòn tấn công của bạn thêm _%s%%._ items.rings.ringoffuror.combined_stats=Những chiếc nhẫn được trang bị của bạn đang kết hợp sức mạnh của chúng, tăng tốc độ của các đòn tấn công của bạn thêm tổng cộng _%s%%_. items.rings.ringoffuror.upgrade_stat_name_1=Tăng tốc độ tấn công -items.rings.ringoffuror.desc=Chiếc nhẫn tạo ra một cơn giận dữ bên trong người mặc, cho phép họ tấn công nhanh hơn. Một chiếc nhẫn bị nguyền sẽ thay vào đó làm chậm tốc độ tấn công của người đeo. +items.rings.ringoffuror.desc=Chiếc nhẫn tạo ra một cơn giận dữ bên trong người đeo, cho phép họ tấn công nhanh hơn. Một chiếc nhẫn bị nguyền sẽ thay vào đó làm chậm tốc độ tấn công của người đeo. items.rings.ringofhaste.name=nhẫn nhanh nhẹn items.rings.ringofhaste.stats=Khi được đeo, chiếc nhẫn này sẽ tăng tốc độ di chuyển của bạn thêm _%s%%._ @@ -1890,7 +1890,7 @@ items.weapon.melee.greataxe.stats_desc=Vũ khí này nặng không tưởng. items.weapon.melee.greataxe.ability_name=báo thù items.weapon.melee.greataxe.typical_ability_desc=Kiếm sĩ có thể thực hiện một đòn _trả thù_ với một cây rìu lớn nếu sinh lực của cô dưới mức 50%%. Đòn tấn công hủy diệt này thường gây _%1$d-%2$d sát thương,_ chắc chắn sẽ trúng, và diễn ra tức thì nếu nó giết một kẻ địch. items.weapon.melee.greataxe.ability_desc=Kiếm sĩ có thể thực hiện một đòn _trả thù_ với một cây rìu lớn nếu sinh lực của cô dưới mức 50%%. Đòn tấn công hủy diệt này gây _%1$d-%2$d sát thương,_ chắc chắn sẽ trúng, và diễn ra tức thì nếu nó giết một kẻ địch. -items.weapon.melee.greataxe.desc=Phải được vác lên vai, chiếc rìu khổng lồ này nặng thế nào thì mạnh thế ấy. +items.weapon.melee.greataxe.desc=Phải được vác lên vai, chiếc rìu khổng lồ này có sức mạnh ngang với sức nặng của nó. items.weapon.melee.greatshield.name=khiên lớn items.weapon.melee.greatshield.typical_stats_desc=Vũ khí này thông thường sẽ đỡ 0-%d sát thương. Mức độ đỡ đòn tỉ lệ thuận với số lượng nâng cấp. diff --git a/core/src/main/assets/messages/items/items_zh-hant.properties b/core/src/main/assets/messages/items/items_zh-hant.properties index d63a71047..13923f569 100644 --- a/core/src/main/assets/messages/items/items_zh-hant.properties +++ b/core/src/main/assets/messages/items/items_zh-hant.properties @@ -74,8 +74,8 @@ items.armor.glyphs.viscosity.desc=這種刻印可以儲存對穿戴者造成的 ###armor items.armor.armor.ac_detach=拆卸 items.armor.armor.detach_seal=你將紋章從護甲上摘了下來。 -items.armor.armor.equip_cursed=這件護甲生疼地勒住了你。 -items.armor.armor.identify=你對你的護甲已經足夠熟悉並且可以因此將其完全鑑定。 +items.armor.armor.equip_cursed=這件護甲緊緊地勒住了你,令你疼痛。 +items.armor.armor.identify=你對身上的護甲了解充分,已完全鑑定其屬性。 items.armor.armor.hardening_gone=你護甲上的硬化效果被損耗掉了! items.armor.armor.incompatible=不同種類的魔法互相衝突,消除了護甲上的刻印! items.armor.armor.curr_absorb=這件_%1$d階_護甲能抵擋_%2$d~%3$d點傷害_並且需要_%4$d點力量_來正常使用。 @@ -200,7 +200,7 @@ items.artifacts.cloakofshadows.ac_stealth=潛行 items.artifacts.cloakofshadows.cooldown=你的斗篷還需要%d回合來重新激活。 items.artifacts.cloakofshadows.cursed=詛咒封鎖了斗篷的魔力。 items.artifacts.cloakofshadows.no_charge=你的斗篷充能不足無法使用。 -items.artifacts.cloakofshadows.desc=這是盜賊多年前從皇家軍械庫竊取的一件無價的魔法斗篷。披上時,能夠使你在短時間內完全隱身。\n\n斗篷越用越強大,能使盜賊更頻繁的隱身,持續時間也更長。 +items.artifacts.cloakofshadows.desc=這件無價的魔法斗篷原屬皇家軍械庫,是盜賊多年前親手偷來的贓物。披上時,能夠使盜賊在短時間內完全隱身。\n\n斗篷越用越強大,能使盜賊更頻繁的隱身,持續時間也更長。 items.artifacts.cloakofshadows.discover_hint=此物品是某位英雄的初始裝備。 items.artifacts.cloakofshadows$cloakstealth.no_charge=你的斗篷耗盡了能量。 items.artifacts.cloakofshadows$cloakstealth.levelup=你的斗篷變得更強大了! @@ -368,7 +368,7 @@ items.artifacts.hornofplenty.reject=你的號角並不接受未經烹煮的無 items.artifacts.hornofplenty.maxlevel=你的號角吞噬了食物,並充滿了豐饒之力! items.artifacts.hornofplenty.levelup=號角吞噬了你提供的食物,變得更加強大了。 items.artifacts.hornofplenty.feed=號角吞噬了你提供的食物。 -items.artifacts.hornofplenty.desc=這個號角不能被用來吹奏,不過裝備時它似乎會隨經驗獲取逐漸填充食物。你可以從裡面拿一小份吃掉,或者直接吃到飽。 +items.artifacts.hornofplenty.desc=這隻號角吹不出聲音,裝備在身上時,卻似乎能隨經驗值增長,於腔內生成食物。你可以從裡面拿一小份吃掉,或者直接吃到飽。 items.artifacts.hornofplenty.desc_hint=也許可以通過給予它食物的能量來增加號角的力量。 items.artifacts.hornofplenty.desc_cursed=被詛咒的號角把自己綁在了你的身邊,它似乎在渴望得到食物而不是製造食物。 @@ -729,7 +729,7 @@ items.potions.potionofexperience.name=經驗藥劑 items.potions.potionofexperience.desc=多場戰鬥積累而來的經驗被濃縮為液態,這種藥劑能夠瞬間提升你的等級。 items.potions.potionoffrost.name=冰霜藥劑 -items.potions.potionoffrost.desc=一旦暴露在空氣里,這種化學藥劑會揮發成為一片寒氣。 +items.potions.potionoffrost.desc=一旦暴露在空氣裡,這種化學藥劑會揮發成為一片寒氣。 items.potions.potionofhaste.name=極速藥劑 items.potions.potionofhaste.energetic=你感到精力充沛! @@ -805,7 +805,7 @@ items.potions.elixirs.elixirofaquaticrejuvenation$aquahealing.name=水靈治療 items.potions.elixirs.elixirofaquaticrejuvenation$aquahealing.desc=你暫時獲得了如同黏咕一樣的恢復能力。 \n\n當站在水面上時,你每回合都能夠回復少量生命值。 生命值全滿或離開水面時會暫停該效果。\n\n水靈恢復持續時長:%d。 items.potions.elixirs.elixirofdragonsblood.name=龍血秘藥 -items.potions.elixirs.elixirofdragonsblood.desc=飲用後,這種秘藥會使飲用者的血管里充斥著烈焰的力量。 這種效果能讓引用者對火焰完全免疫,並且還能通過物理攻擊點燃敵人。 +items.potions.elixirs.elixirofdragonsblood.desc=飲用後,這種秘藥會使飲用者的血管裡充斥著烈焰的力量。 這種效果能讓引用者對火焰完全免疫,並且還能通過物理攻擊點燃敵人。 items.potions.elixirs.elixiroffeatherfall.name=羽落秘藥 items.potions.elixirs.elixiroffeatherfall.light=你覺得自己身輕如燕! @@ -886,7 +886,7 @@ items.potions.exotic.potionofshroudingfog.name=暗夜迷霧合劑 items.potions.exotic.potionofshroudingfog.desc=瓶中的合劑遇到空氣就會快速釋放出能完全阻擋敵人可視範圍的濃濃煙霧。 items.potions.exotic.potionofsnapfreeze.name=極速冰凍合劑 -items.potions.exotic.potionofsnapfreeze.desc=一旦暴露在空氣里,這種化學混合物會瞬間凍結並束縛住範圍內一切物件。 +items.potions.exotic.potionofsnapfreeze.desc=一旦暴露在空氣裡,這種化學混合物會瞬間凍結並束縛住範圍內一切物件。 items.potions.exotic.potionofstamina.name=精力回復合劑 items.potions.exotic.potionofstamina.desc=喝這種奇怪的甜液體將給你帶來巨大的能量提升,讓你以更快的速度運行很長一段時間。 @@ -979,7 +979,7 @@ items.rings.ring.agate=瑪瑙戒指 items.rings.ring.equip_cursed=這枚戒指緊緊箍住了你的手指! items.rings.ring.unknown_desc=這枚金屬環鑲嵌著一顆在黑暗中閃爍光芒的大塊寶石。誰知道戴上後會有什麼效果? items.rings.ring.known=這是個%s。 -items.rings.ring.identify=你對手中的戒指已經足夠熟悉並將其完全鑑定。 +items.rings.ring.identify=你對手中的戒指了解充分,已完全鑑定其屬性。 items.rings.ring.cursed_worn=由於這枚戒指被詛咒,你無力將其取下。 items.rings.ring.curse_known=你能感覺到這枚戒指裡潛伏著一股充滿惡意的魔力。 items.rings.ring.not_cursed=這枚戒指沒有被詛咒。 @@ -1265,7 +1265,7 @@ items.spells.beaconofreturning.desc=這種複雜的晶住給予了使用者無 items.spells.curseinfusion.name=強力詛咒菱晶 items.spells.curseinfusion.inv_title=詛咒一件物品 -items.spells.curseinfusion.desc=這種菱晶會為裝備賦予和在DM-300內找到的邪惡能量一樣的魔法。對任一裝備使用時,該物品將會被詛咒,且將失去其原本的附加魔法特性。\n\n對武器、護甲及法杖使用時,它們會在被詛咒的同時獲得升級。升級效果不會多次疊加,且會在詛咒被解除時消失。\n\n也可以對已詛咒的武器或護甲使用來變更上面的詛咒效果。 +items.spells.curseinfusion.desc=這種菱晶會為裝備賦予和在DM-300內找到的邪惡能量一樣的魔法。對任一裝備使用時,該物品將會被詛咒,且將失去其原本的附加魔法特性。\n\n對武器、護甲及法杖使用時,它們會在被詛咒的同時獲得升級,但升級效果不會多次疊加。詛咒帶來的負面效果解除時,此種升級效果也隨之消散。\n\n也可以對已詛咒的武器或護甲使用來變更上面的詛咒效果。 items.spells.spell.ac_cast=施放 items.spells.spell.no_magic=你無法在魔法免疫的情況下使用法術結晶。 @@ -1431,7 +1431,7 @@ items.trinkets.mossyclump.typical_stats_desc=通常此飾品會使非特殊樓 items.trinkets.mossyclump.stats_desc=以目前的等級,此飾品會使非特殊樓層有_%d%%_的機率變成繁茂或者含水樓層。\n\n此飾品升級時所需的能量較多。 items.trinkets.parchmentscrap.name=咒術殘頁 -items.trinkets.parchmentscrap.desc=這張小羊皮紙似乎是一張卷軸的一部份。它還保留了一部份的魔力,且似乎正在影響這座地下城中找到的武器及護甲。 +items.trinkets.parchmentscrap.desc=這張小羊皮紙似乎是某張卷軸的一部份。它還保留了一部份的魔力,且似乎正在影響這座地下城中找到的武器及護甲。 items.trinkets.parchmentscrap.typical_stats_desc=通常此飾品會使附魔及刻印的出現率提高_%d倍_,且增加_%s倍_詛咒的出現率。魔杖、戒指及神器不會受到影響。\n\n此飾品升級時所需的能量較多。 items.trinkets.parchmentscrap.stats_desc=以目前的等級,此飾品會使附魔及刻印的出現率提高_%d倍_,且增加_%s倍_詛咒的出現率。魔杖、戒指及神器不會受到影響。\n\n此飾品升級時所需的能量較多。 @@ -1451,9 +1451,9 @@ items.trinkets.saltcube.typical_stats_desc=在非頭目戰的情況下,通常 items.trinkets.saltcube.stats_desc=在非頭目戰的情況下,以目前的等級,此飾品會使你的飢餓消耗延緩_%1$s%%_,但也使自然回血的頻率降低_%2$s%%_。 items.trinkets.shardofoblivion.name=遺忘碎片 -items.trinkets.shardofoblivion.desc=在煉金釜的作用下,這塊小小的詛咒鐵片變成了……呃……虛空?光線在它的周圍被扭曲,在沒被外力作用下會懸停在原處。碎片似乎神奇地從你的無知中汲取力量,所以還是最好別對此想太多。 -items.trinkets.shardofoblivion.typical_stats_desc=通常此飾品會根據你正在裝備或近期使用的每一件未鑑定裝備以增加敵人掉落它們的所有物的機率提升20%%,最多計算_%d件_。這個飾品也會阻止你以任何方式鑑定裝備,使你只能透過碎片來得知符合鑑定條件裝備的屬性。 -items.trinkets.shardofoblivion.stats_desc=以目前的等級,此飾品會根據你正在裝備或近期使用的每一件未鑑定裝備以增加敵人掉落它們的所有物的機率提升20%%,最多計算_%d件_。這個飾品也會阻止你以任何方式鑑定裝備,使你只能透過碎片來得知符合鑑定條件裝備的屬性。 +items.trinkets.shardofoblivion.desc=在煉金釜的作用下,這塊小小的詛咒鐵片變成了……呃……虛空?光線在它的周圍會被扭曲,在沒被外力作用下會懸停在原處。碎片似乎神奇地從你的無知中汲取力量,所以還是最好別對此想太多。 +items.trinkets.shardofoblivion.typical_stats_desc=通常此飾品會根據你正在裝備或近期使用的每一件未完全鑑定裝備以增加敵人掉落它們的所有物的機率提升20%%,最多計算_%d件_。這個飾品也會阻止你以任何方式鑑定裝備,使你只能透過碎片來得知符合鑑定條件裝備的屬性。 +items.trinkets.shardofoblivion.stats_desc=以目前的等級,此飾品會根據你正在裝備或近期使用的每一件未完全鑑定裝備以增加敵人掉落它們的所有物的機率提升20%%,最多計算_%d件_。這個飾品也會阻止你以任何方式鑑定裝備,使你只能透過碎片來得知符合鑑定條件裝備的屬性。 items.trinkets.shardofoblivion.ac_identify=鑑定 items.trinkets.shardofoblivion.identify_prompt=鑑定一件物品 items.trinkets.shardofoblivion.identify_ready=已符合鑒定條件的物品:%s。請使用遺忘碎片以將此裝備變為已鑑定狀態。 @@ -1519,7 +1519,7 @@ items.wands.wand.ac_zap=釋放 items.wands.wand.fizzles=你的法杖滋滋作響;一定是沒能量了。 items.wands.wand.no_magic=你的法杖滋滋作響;你不能在魔法免疫時使用法杖。 items.wands.wand.self_target=你不能瞄準你自己! -items.wands.wand.identify=你對你的法杖已經足夠熟悉並將其完全鑒定。 +items.wands.wand.identify=你對你的法杖了解充分,已完全鑑定其屬性。 items.wands.wand.resin_one=這根法杖已透過奧術樹脂升級了_1級_。 items.wands.wand.resin_many=這根法杖已透過奧術樹脂升級了_%d級_。 items.wands.wand.cursed=這根法杖受到了詛咒,導致它的魔法混亂而隨機。 @@ -2239,7 +2239,7 @@ items.weapon.spiritbow.stats=這把弓不能直接升級,但是會隨著你等 items.weapon.spiritbow.desc=一把由遠古靈木製成的弓,弓弦和弓身的刻紋散發著蒼藍色的幽光。 拉開弓弦時,一發魔法箭矢會生成在弓身一側向目標飛去。 items.weapon.spiritbow.discover_hint=此物品是某位英雄的初始裝備。 -items.weapon.weapon.identify=你對手中的武器已經足夠熟悉並將其完全鑑定。 +items.weapon.weapon.identify=你對手上的武器了解充分,已完全鑑定其屬性。 items.weapon.weapon.too_heavy=因為你的力量不足,該武器會降低你的攻速和準度,並讓你無法偷襲。 items.weapon.weapon.excess_str=你的額外力量讓你在使用這件武器時能夠造成_0~%d點額外傷害_。 items.weapon.weapon.hardening_gone=你武器上的硬化效果被損耗掉了! diff --git a/core/src/main/assets/messages/journal/journal_eo.properties b/core/src/main/assets/messages/journal/journal_eo.properties index 5183bb309..a28b3ff72 100644 --- a/core/src/main/assets/messages/journal/journal_eo.properties +++ b/core/src/main/assets/messages/journal/journal_eo.properties @@ -39,7 +39,7 @@ journal.document.adventurers_guide.intro.body=Saluton kara aventuristo, vi nun l journal.document.adventurers_guide.examining.title=Ekzameni journal.document.adventurers_guide.examining.body=Estas grave akiri informojn pri viaj kontraŭuloj kaj pri ĉirkaŭaĵo, anstataŭ senpripense kuri antaŭen! Ellaboru kutimon ekzameni ĉion novan.\n\n(Vi povas ekzameni objektojn uzante la butonon de lupeo kaj sekve elekti tion, pri kio vi volas akiri informojn. Vi ankaŭ povas sciiĝi pri nuntempaj efikoj per elekti iliajn bildsimbolojn.) journal.document.adventurers_guide.surprise_attacks.title=Surprizaj atakoj -journal.document.adventurers_guide.surprise_attacks.body=Surprizaj atakoj ĉiam trafas, tio iĝas ilin efikaj kontraŭ evitpovaj malamikoj – kiel serpentoj kaj fifantomoj.\n\nKiam malamiko postkuras vin, vi povas surprizi lin tuj post trairi pordon; aŭ tuj post alia situacio en kiu malamiko perdas vin de sia vidatingo. +journal.document.adventurers_guide.surprise_attacks.body=Surprizaj atakoj ĉiam trafas, tio iĝas ilin efikaj kontraŭ evitpovaj malamikoj – kiel serpentoj kaj fifantomoj.\n\nKiam malamiko postkuras vin, vi povas surprizi lin tuj post trairi pordon aŭ tuj post alia situacio en kiu malamiko perdas vin de sia vidatingo. journal.document.adventurers_guide.identifying.title=Identigi aĵojn journal.document.adventurers_guide.identifying.body=Koloroj de eliksiroj kaj simboloj sur skribrulaĵoj estas malsamaj por ĉiu labirinto (nova ludo). Neidentigita armaĵo feliĉe povas esti plibonigita aŭ ensorĉita, tamen ĝi ankaŭ povas esti malbenita!\n\nSkribrulaĵoj de identigo, plibonigo kaj senmalbenigo estas tre utilaj por minimumigi la riskon pro uzi neidentigitaj armaĵoj.\n\n(Vi povas trovi la liston de ĉiuj identigitaj objektoj en la katalogo de objektoj en via taglibro.) journal.document.adventurers_guide.food.title=Zorgi malsaton diff --git a/core/src/main/assets/messages/journal/journal_pl.properties b/core/src/main/assets/messages/journal/journal_pl.properties index 26b96700a..d859b516e 100644 --- a/core/src/main/assets/messages/journal/journal_pl.properties +++ b/core/src/main/assets/messages/journal/journal_pl.properties @@ -45,13 +45,13 @@ journal.document.adventurers_guide.identifying.body=Kolory mikstur oraz symbole journal.document.adventurers_guide.food.title=Postępowanie z głodem journal.document.adventurers_guide.food.body=Odpowiedzialne racjonowanie żywności to jedna z najważniejszych rzeczy, które możesz zrobić, aby zwiększyć swoje szanse na przetrwanie. Nie musisz jeść od razu, gdy zgłodniejesz!\n\nKiedy nie jesteś wygłodzony, powoli regenerujesz zdrowie. Tak więc, jedząc przy pełnym zdrowiu, ta regeneracja zostanie zmarnowana!\n\nJeśli zdecydujesz, kiedy jesz, w zależności od stanu twojego zdrowia, żywność wystarczy ci na dużo dłużej. journal.document.adventurers_guide.alchemy.title=Alchemia i Relikty -journal.document.adventurers_guide.alchemy.body=Jeśli uważasz jakiś przedmiot jednorazowego użytku za zbędny, możesz go użyć jako składnika w tyglu alchemicznym lub przekształcić w uniwersalną energię alchemiczną. Przekształcanie zwojów i mikstur w energię, również je identyfikuje!\n\nRelikty są jedyną częścią ekwipunku, która powstaje i jest ulepszana dzięki alchemii. Można je stworzyć z niewielkiej ilości energii alchemicznej i magicznego katalizatora. \n\n(Pierwszy tygiel alchemiczny znajdziesz na 3. lub 4. piętrze lochu. W pobliżu tych tygli znajdziesz strony z książki od alchemii.) +journal.document.adventurers_guide.alchemy.body=Jeśli uważasz jakiś przedmiot jednorazowego użytku za zbędny, możesz go użyć jako składnika w tyglu alchemicznym lub przekształcić w uniwersalną energię alchemiczną. Przekształcanie zwojów i mikstur w energię pozwala je zidentyfikować!\n\nRelikty są jedyną częścią ekwipunku, która jest tworzona i ulepszana z pomocą alchemii. Można je stworzyć z niewielkiej ilości energii alchemicznej i magicznego katalizatora. \n\n(Pierwszy tygiel alchemiczny znajdziesz na 3. lub 4. piętrze lochu. W pobliżu tych tygli znajdziesz strony z książki od alchemii.) journal.document.adventurers_guide.dieing.title=Radzenie Sobie z Porażką journal.document.adventurers_guide.dieing.body=Eksploracja podziemi to bardzo niebezpieczny zawód i większość poszukiwaczy przygód kończy tragicznie.\n\nOdrobina szczęścia pomaga, ale najlepsi poszukiwacze przygód korzystają z każdej sztuczki, aby zwiększyć swoje szanse.\n\n(Nie zniechęcaj się, jeśli często giniesz, ta gra jest trudna! Skoncentruj się na nauce gry i stopniowym doskonaleniu, a nie wygrywaniu od razu.) journal.document.adventurers_guide.searching.title=Przeszukiwanie -journal.document.adventurers_guide.searching.body=Podziemia przepełnione są tajnymi przejściami i pułapkami, które na pierwszy rzut oka wydają się niewidoczne. Możesz poświęcić trochę czasu na dokładniejsze poszukiwania, jeśli masz podejrzenie że w pobliżu znajdują się ukryte drzwi lub pułapki.\n\n(Możesz przeszukać wszystkie pola wokół ciebie, używając dwukrotnie przycisku z lupą. Być może w pobliżu miejsca, gdzie znalazłeś tę stronę, są jakieś ukryte drzwi!) +journal.document.adventurers_guide.searching.body=Podziemia są pełne tajnych przejść i pułapek które są niewidoczne na pierwszy rzut oka. Możesz poświęcić trochę czasu na dokładniejsze poszukiwania, jeśli masz podejrzenie, że w pobliżu znajdują się ukryte drzwi lub pułapki.\n\n(Możesz przeszukać wszystkie pola wokół siebie, używając dwukrotnie przycisku z lupą. Być może w pobliżu miejsca, gdzie znaleziono tę stronę, są jakieś ukryte drzwi!) journal.document.adventurers_guide.strength.title=Siła -journal.document.adventurers_guide.strength.body=W lochu nie ma czasu na trening z odnalezioną bronią czy pancerzem, więc aby ich efektywnie używać, potrzebny ci będzie zastrzyk czystej energii.\n\nMikstury siły oraz zwoje ulepszenia są najlepszym remedium na spełnienie wymogów wyposażenia wyższego kręgu.\n\nWażna rzeczą jest dążenie do używania przedmiotów wyższych kręgów, acz nie należy kompletnie ignorować wyposażenia które jest zdatne do użytku w tym, konkretnym momencie. +journal.document.adventurers_guide.strength.body=W lochu nie ma czasu na trening z odnalezioną bronią czy pancerzem, więc aby ich efektywnie używać, potrzebny jest zastrzyk czystej siły.\n\nMikstury siły oraz zwoje ulepszenia są najlepszym remedium na spełnienie wymogów wyposażenia wyższego kręgu.\n\nWażną rzeczą jest dążenie do używania przedmiotów wyższych kręgów, lecz lepiej nie ignorować całkowicie wyposażenia, które możesz wykorzystać już teraz. journal.document.adventurers_guide.upgrades.title=Ulepszenia journal.document.adventurers_guide.upgrades.body=Im głębiej zapuszczasz się w loch, tym bardziej istotne jest używanie magicznie zaklętego wyposażenia wysokiego kręgu, które wymaga siły, aby móc je skutecznie używać.\n\nRóżdżki, pierścienie i artefakty nie wymagają siły, ale posiadają ograniczoną liczbę użyć, bądź są mało przydatne w bezpośrednim starciu.\n\nPodejmowanie właściwych decyzji w kwestii ulepszeń jest nad wyraz istotne dla przetrwania początkowych części lochu oraz odpowiedniego przygotowania na trudy głębszych poziomów. journal.document.adventurers_guide.looting.title=Skutecznie łupienie @@ -59,7 +59,7 @@ journal.document.adventurers_guide.looting.body=Pomieszczenia za zamkniętymi dr journal.document.adventurers_guide.levelling.title=Zdobywanie doświadczenia journal.document.adventurers_guide.levelling.body=Zdobywanie poziomów doświadczenia zwiększa twoje statystyki i nagradza cię punktami talentów, które mogą mieć duże znaczenie w walce. Najlepiej zdobywać co najmniej jeden poziom na każde piętro lochu.i\n\nPrzebiegnięcie przez loch i uniknięcie walki lub eksploracji może być kuszące, ale taka taktyka pozbawi cię cennych zasobów i doświadczenia.\n\n(Możesz zobaczyć informacje o swoim bohaterze, w tym o jego doświadczeniu, na panelu statystyk w rogu interfejsu. Wybierz portret swojego bohatera, aby zobaczyć jeszcze więcej informacji.) journal.document.adventurers_guide.positioning.title=Ustawianie się -journal.document.adventurers_guide.positioning.body=Strategia jest równie ważna, jak wyposażenie. Niekorzystne sytuacje, takie jak bycie otoczonym, zazwyczaj mogą być uniknięte poprzez zajmowanie odpowiednich pozycji. \n\nDla przykładu, większość lochów ma wąskie korytarze, zmuszające przeciwników do walki w pojedynkę. Te korytarze często posiadają też drzwi, przydatne przy atakach z zaskoczenia! \n\nIstnieje wiele mniejszych sposobów na wykorzystanie elementów otoczenia, takich jak trawa, woda, przepaści czy pułapki, na swoją korzyść. +journal.document.adventurers_guide.positioning.body=Strategia jest równie ważna co wyposażenie. Możesz uniknąć wiele niekorzystnych sytuacji, takich jak zostanie otoczonym, poprzez zajmowanie odpowiednich pozycji.\n\nDla przykładu, większość lochów ma wąskie korytarze, zmuszające przeciwników do walki w pojedynkę. Korytarze często mają też drzwi przydatne przy atakach z zaskoczenia!\n\nInne elementy otoczenia takie jak trawa, woda, przepaść czy pułapki też możesz wykorzystywać w pewnym stopniu na twoją korzyść. journal.document.adventurers_guide.magic.title=Ataki magiczne journal.document.adventurers_guide.magic.body=Ataki magiczne przenikają przez zbroję i są trudne do uniknięcia. Oznacza to, że obrażenia różdżek są niemal niezawodne, ale czyni to władających magią przeciwników bardzo niebezpiecznymi!\n\nAtaki magiczne zawsze mają jakąś wadę. Różdżki mają ograniczoną liczbę ładunków, a magiczni przeciwnicy zazwyczaj nie będą mogli używać swojej magii w zwarciu.\n\nPodczas starcia z wrogami, którzy używają magii, ważne jest nauczenie się, jak uniemożliwić im używanie jej przeciwko tobie. @@ -69,7 +69,7 @@ journal.document.alchemy_guide.potions.body=Witaj w "Praktycznych zastosowaniach journal.document.alchemy_guide.stones.title=Tworzenie kamieni runicznych journal.document.alchemy_guide.stones.body=Wrzucenie zwoju do tygla alchemicznego sprawi, że dwa kamienie wchłoną jego magię. W ten sposób można zidentyfikować zwój i otrzymać kamienie runiczne! journal.document.alchemy_guide.energy_food.title=Energia i jedzenie -journal.document.alchemy_guide.energy_food.body=Wiele receptur wymaga skrystalizowanej energii alchemicznej, wytwarzanej poprzez rozkładanie przedmiotów jednorazowego użytku w tyglu alchemicznym. Przekształcanie zwojów i mikstur w energię, również je identyfikuje..\n\nCzęść receptur wymagających energii to czysta magia, aczkolwiek tym bliżej jest do tradycjonalnej kuchni. +journal.document.alchemy_guide.energy_food.body=Wiele receptur wymaga skrystalizowanej energii alchemicznej, wytwarzanej poprzez rozkładanie przedmiotów jednorazowego użytku w tyglu alchemicznym. Przekształcanie zwojów i mikstur w energię pozwala je zidentyfikować.\n\nCzęść receptur wymagających energii to czysta magia, aczkolwiek tym bliżej jest do tradycjonalnej kuchni. journal.document.alchemy_guide.exotic_potions.title=Egzotyczne eliksiry journal.document.alchemy_guide.exotic_potions.body=Połącz mikstury z energią, aby tworzyć egzotyczne eliksiry. Są one potężniejsze od zwykłych, choć czasami mają nieco inne działanie. journal.document.alchemy_guide.exotic_scrolls.title=Egzotyczne zwoje diff --git a/core/src/main/assets/messages/levels/levels_zh-hant.properties b/core/src/main/assets/messages/levels/levels_zh-hant.properties index e5ce01378..0c2649feb 100644 --- a/core/src/main/assets/messages/levels/levels_zh-hant.properties +++ b/core/src/main/assets/messages/levels/levels_zh-hant.properties @@ -45,7 +45,7 @@ levels.traps.burningtrap.name=烈焰陷阱 levels.traps.burningtrap.desc=踩進這個陷阱會點燃某種化學混合物,導致周圍小塊區域起火。 levels.traps.chillingtrap.name=寒氣陷阱 -levels.traps.chillingtrap.desc=被觸發時,這個陷阱裡的化學藥劑會迅速凍結周圍的空氣。 +levels.traps.chillingtrap.desc=觸發時,這個陷阱裡的化學藥劑會迅速凍結周圍的空氣。 levels.traps.confusiontrap.name=致眩氣體陷阱 levels.traps.confusiontrap.desc=觸發這個陷阱後,排氣孔將噴出一片混亂氣體。 @@ -71,7 +71,7 @@ levels.traps.explosivetrap.name=爆炸陷阱 levels.traps.explosivetrap.desc=這個陷阱包含一些粉狀炸藥和一個觸發機制。觸發它會導致一定範圍的爆炸。 levels.traps.flashingtrap.name=閃光陷阱 -levels.traps.flashingtrap.desc=被觸發時,這個陷阱將點燃儲存在裡面的強效閃光粉,使受害者暫時失明、殘廢、並受到傷害。\n\n由於閃光粉的存量極大,陷阱被觸發再多次,也不會失效。 +levels.traps.flashingtrap.desc=觸發時,這個陷阱將點燃儲存在裡面的強效閃光粉,使受害者暫時失明、殘廢、並受到傷害。\n\n由於閃光粉的存量極大,陷阱被觸發再多次,也不會失效。 levels.traps.flocktrap.name=羊群陷阱 levels.traps.flocktrap.desc=也許是個來自一些業餘法師的玩笑,觸發這個陷阱就會召喚一群魔法綿羊。 @@ -83,7 +83,7 @@ levels.traps.gatewaytrap.name=通道陷阱 levels.traps.gatewaytrap.desc=這種特殊的傳送陷阱可以被反覆觸發並且總是通向同樣的目的地。 levels.traps.geysertrap.name=噴泉陷阱 -levels.traps.geysertrap.desc=當被觸發時,大量的水會從中噴湧而出,傷害火屬性單位,沖退周圍的所有單位,熄滅火焰,並將周圍的地形轉化為水。 +levels.traps.geysertrap.desc=觸發時,大量的水會從中噴湧而出,傷害火屬性單位,沖退周圍的所有單位,熄滅火焰,並將周圍的地形轉化為水。 levels.traps.gnollrockfalltrap.name=豺狼落石陷阱 levels.traps.gnollrockfalltrap.desc=這種落石陷阱是一種魔法產物。觸發時它會導致岩石鬆動並立即從上方掉落在其周圍 5x5 的區域內。由於礦坑裡的石頭比上面的軟,所以造成的傷害會比普通的落石陷阱低,但也使得護甲不能很好的吸收傷害。由於這礦坑的某些地方有被支柱支撐,落石也不會掉到它附近。\n\n_這陷阱跟上面的一樣不長眼,對這裡的生物它都傷得了。_ diff --git a/core/src/main/assets/messages/levels/levels_zh.properties b/core/src/main/assets/messages/levels/levels_zh.properties index ecaaacb04..9aa30f26a 100644 --- a/core/src/main/assets/messages/levels/levels_zh.properties +++ b/core/src/main/assets/messages/levels/levels_zh.properties @@ -177,8 +177,8 @@ levels.caveslevel.exit_desc=通向下一层的梯子。 levels.caveslevel.high_grass_desc=高耸的蘑菇群遮挡了你的视线。 levels.caveslevel.wall_deco_desc=岩壁上能隐约看见金属矿脉的纹路,难道是黄金? levels.caveslevel.bookshelf_desc=到底会有谁需要在洞窟里摆上这么个书架? -levels.caveslevel.region_deco_name=金属结构 -levels.caveslevel.region_deco_desc=一个大型全金属结构,可能是在矮人过去在此处采矿时建造的。你认为你在其上层看到了早已废弃的矿车轨道。 +levels.caveslevel.region_deco_name=金属架构 +levels.caveslevel.region_deco_desc=一个大型全金属架构,可能是在矮人过去在采矿时建造的。其上层应当有废弃了许久的矿车轨道。 levels.citylevel.water_name=异色水潭 levels.citylevel.high_grass_name=茂盛花朵 diff --git a/core/src/main/assets/messages/misc/misc_vi.properties b/core/src/main/assets/messages/misc/misc_vi.properties index 3a36535ff..ee2a28a04 100644 --- a/core/src/main/assets/messages/misc/misc_vi.properties +++ b/core/src/main/assets/messages/misc/misc_vi.properties @@ -132,7 +132,7 @@ badges$badge.no_monsters_slain.title=Người yêu hòa bình badges$badge.no_monsters_slain.desc=Vượt qua một tầng mà không tiêu diệt kẻ thù nào badges$badge.grim_weapon.title=Thần chết badges$badge.grim_weapon.desc=Đánh bại kẻ thù với một vũ khí có phù phép tử thần -badges$badge.piranhas.title=Người câu cá bất tiện +badges$badge.piranhas.title=Người câu cá lạ thường badges$badge.piranhas.desc=Tiêu diệt 6 con piranha trong một lượt chơi badges$badge.boss_challenge_1.title=Chiến thắng hoàn chỉnh badges$badge.boss_challenge_1.desc=Đánh bại trùm của khu cống ngầm mà không cho nó sử dụng cú đánh sạc hoặc hồi máu trong nước. diff --git a/core/src/main/assets/messages/misc/misc_zh.properties b/core/src/main/assets/messages/misc/misc_zh.properties index 59b1a7541..6eec0c29a 100644 --- a/core/src/main/assets/messages/misc/misc_zh.properties +++ b/core/src/main/assets/messages/misc/misc_zh.properties @@ -204,11 +204,11 @@ badges$badge.unlock_cleric.title=解锁牧师! badges$badge.unlock_cleric.desc=完全净化任何一件被诅咒装备的诅咒以解锁牧师 badges$badge.enemy_hazards.title=安全隐患 badges$badge.enemy_hazards.desc=在一局游戏中通过特殊地形(陷阱、植物或深渊)击败10个敌人 -badges$badge.many_buffs.title=狂乱的鸡尾酒 +badges$badge.many_buffs.title=五彩缤纷 badges$badge.many_buffs.desc=同时拥有至少10种增益/减益 -badges$badge.pacifist_ascent.title=光荣凯旋 +badges$badge.pacifist_ascent.title=和平凯旋 badges$badge.pacifist_ascent.desc=将其诅咒未曾减弱的Yendor护符带出地牢 -badges$badge.taking_the_mick.title=弄巧成拙 +badges$badge.taking_the_mick.title=虎口弄嘲 badges$badge.taking_the_mick.desc=以一把至少20级的镐子对最终boss打出致命一击 challenges.no_food=缩餐节食 diff --git a/core/src/main/assets/messages/plants/plants_zh.properties b/core/src/main/assets/messages/plants/plants_zh.properties index ba5a4e0da..7339bb31c 100644 --- a/core/src/main/assets/messages/plants/plants_zh.properties +++ b/core/src/main/assets/messages/plants/plants_zh.properties @@ -1,6 +1,6 @@ plants.blandfruitbush.name=无味果 plants.blandfruitbush.desc=腐莓的远亲,来自无味果树丛的梨状产物,尝起来犹如一团泥巴。果实粗糙且松软,但并没有毒性。也许可以煮食。 -plants.blandfruitbush.discover_hint=你可在地牢中随机发现该植物。 +plants.blandfruitbush.discover_hint=这种植物有几率在地牢中生成。 plants.blandfruitbush$seed.name=无味果之种 plants.blindweed.name=致盲草 @@ -37,7 +37,7 @@ plants.icecap.warden_desc=_守望者_能将有害的冰冻转化为短时的寒 plants.icecap$seed.name=冰冠花之种 plants.plant.warden_desc=守望者踩踏这株植物不会获得额外效果。 -plants.plant.discover_hint=你可通过在地牢中随机发现或使用其种子种植该植物。 +plants.plant.discover_hint=这种植物和它的种子有几率在地牢中生成。 plants.plant$seed.seed_of=%s之种 plants.plant$seed.ac_plant=种植 plants.plant$seed.info=把这粒种子丢到你想长出一株植物的地方。\n\n%s @@ -46,9 +46,9 @@ plants.plant$seed$placeholder.name=种子 plants.rotberry.name=腐莓 plants.rotberry.desc=未成熟的腐莓丛结出的莓果尝起来更像是甜蜜的死亡。经过成年累月的生长,这株腐莓丛终会成熟为另一棵腐莓核心。被踩踏后,这株未成熟的腐莓会释放少量毒气。 plants.rotberry.warden_desc=遭到践踏时腐莓丛通常只会喷出一小股毒气,但_守望者_却能联结其中的魔力,在短时间内提升力量! -plants.rotberry.discover_hint=你可在某个任务中使用其种子种植该植物。 +plants.rotberry.discover_hint=这种植物的种子将在某个特殊任务中出现。 plants.rotberry$seed.name=腐莓之种 -plants.rotberry$seed.discover_hint=你可在某个任务中发现该物品。 +plants.rotberry$seed.discover_hint=这件物品将在某个特殊任务中出现。 plants.sorrowmoss.name=断肠苔 plants.sorrowmoss.desc=断肠苔(实为花卉而非苔藓)是一种花瓣利如刀片,表面覆有致命毒液的植物。 diff --git a/core/src/main/assets/messages/windows/windows_eo.properties b/core/src/main/assets/messages/windows/windows_eo.properties index 032721071..1e62c694d 100644 --- a/core/src/main/assets/messages/windows/windows_eo.properties +++ b/core/src/main/assets/messages/windows/windows_eo.properties @@ -231,7 +231,7 @@ windows.wndranking$statstab.challenges=Defioj windows.wndranking$statstab.score=Poentaro windows.wndranking$statstab.str=Povo windows.wndranking$statstab.duration=Luda daŭro -windows.wndranking$statstab.depth=Maksimuma keletaĝo +windows.wndranking$statstab.depth=Maks. keletaĝo windows.wndranking$statstab.ascent=Postvenka supreniro windows.wndranking$statstab.seed=Labirint-ĝermo windows.wndranking$statstab.custom_seed=_Propra ĝermo_ diff --git a/core/src/main/assets/messages/windows/windows_nl.properties b/core/src/main/assets/messages/windows/windows_nl.properties index b95d697ce..832580bb7 100644 --- a/core/src/main/assets/messages/windows/windows_nl.properties +++ b/core/src/main/assets/messages/windows/windows_nl.properties @@ -289,8 +289,8 @@ windows.wndsettings$displaytab.saver=Energiebespaarder windows.wndsettings$displaytab.saver_desc=In de energiebesparingsstand wordt het spel op een kleiner formaat getekend en opgeschaald zodat deze op je scherm past.\n\nHierdoor wordt de vormgeving minder scherp en wordt de menuweergave iets groter, maar worden ook de prestaties en de batterijduur verbeterd.\n\nJe moet het spel waarschijnlijk herstarten om deze verandering te laten werken. windows.wndsettings$displaytab.okay=Oké windows.wndsettings$displaytab.cancel=Annuleren -windows.wndsettings$displaytab.portrait=Overschakelen naar portret -windows.wndsettings$displaytab.landscape=Overschakelen naar landschap +windows.wndsettings$displaytab.portrait=Portretmodus +windows.wndsettings$displaytab.landscape=Landschapsmodus windows.wndsettings$displaytab.brightness=Helderheid windows.wndsettings$displaytab.dark=Donker windows.wndsettings$displaytab.bright=Helder diff --git a/core/src/main/assets/messages/windows/windows_pl.properties b/core/src/main/assets/messages/windows/windows_pl.properties index 9c296198b..bb9764a05 100644 --- a/core/src/main/assets/messages/windows/windows_pl.properties +++ b/core/src/main/assets/messages/windows/windows_pl.properties @@ -371,7 +371,7 @@ windows.wndupgrade.enchant=Ulepszenie tego przedmiotu ma %d%% szans na zniszczen windows.wndupgrade.glyph=Ulepszenie tego przedmiotu ma %d%% szans na zniszczenie glifu! windows.wndupgrade.harden=Ulepszenie tego przedmiotu ma %d%% szans na zniszczenie zahartowania! windows.wndupgrade.resin=Ta różdżka została ulepszona magiczną żywicą, zwykłe ulepszenia zastąpią ulepszenia z żywicy! -windows.wndupgrade.thrown_dust=Bronie z tego zestawu, których nie masz w ekwipunku zamienią się w drobny mak. +windows.wndupgrade.thrown_dust=Bronie z tego zestawu, których nie masz w ekwipunku, rozpadną się w drobny mak. windows.wndupgrade.damage=Obrażenia windows.wndupgrade.blocking=Blokowane Obrażenia windows.wndupgrade.weight=Waga diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/messages/Languages.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/messages/Languages.java index a5afa5d6f..e9d0545c7 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/messages/Languages.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/messages/Languages.java @@ -25,28 +25,28 @@ import java.util.Locale; public enum Languages { ENGLISH("english", "en", Status.O_COMPLETE, null, null), - CHI_SMPL("简体中文", "zh", Status.__UNREVIEW, new String[]{"Chronie_Lynn_Iwa", "Jinkeloid(zdx00793)", "endlesssolitude"}, new String[]{"931451545", "Budding", "Fatir", "Fishbone", "Hcat", "HoofBumpBlurryface", "Horr_lski", "Lery", "Lyn_0401", "Lyx0527", "Ooooscar", "RainSlide", "ShatteredFlameBlast", "SpaceAnchor", "SunsetGlowTheDOGE", "Teller", "hmdzl001", "leo", "tempest102", "户方狸奴"}), + CHI_SMPL("简体中文", "zh", Status.__UNREVIEW, new String[]{"Chronie_Lynn_Iwa", "Jinkeloid(zdx00793)", "endlesssolitude"}, new String[]{"931451545", "Budding", "Fatir", "Fishbone", "Hcat", "HoofBumpBlurryface", "Horr_lski", "Lery", "Lyn_0401", "Lyx0527", "Ooooscar", "RainSlide", "ShatteredFlameBlast", "SpaceAnchor", "SunsetGlowTheDOGE", "Teller", "hmdzl001", "leo", "tempest102", "tequilasunset", "户方狸奴"}), KOREAN("한국어", "ko", Status.__UNREVIEW, new String[]{"Cocoa", "Flameblast12", "GameConqueror", "Korean2017"}, new String[]{"AFS", "N8fall", "WondarRabb1t", "benepaper", "chlrhwnstkd", "ddojin0115", "eeeei", "enjuxx", "hancyel", "linterpreteur", "lemonam", "lsiebnie", "sora0430"}), - RUSSIAN("русский", "ru", Status.__UNREVIEW, new String[]{"AprilRain(Vadzim Navumaû)", "ConsideredHamster", "Dominowood371", "Inevielle", "apxwn", "yarikonline"}, new String[]{"5r", "AngryPotato", "AttHawk46", "BlueberryShortcake", "CatGirlSasha", "Enwviun", "HerrGotlieb", "HoloTheWise", "Ilbko", "JleHuBbluKoT", "KirStaLong", "MrXantar", "Nikets", "OneDuo", "Originalej0name", "Provitia", "Raymundo", "Roycce", "Shamahan", "Thomasg63", "XAutumn", "Ya6lo4ko", "chelikchelik", "dasfan123", "ifritdiezel", "kirusyaga", "kptmx", "leondorus", "long_live_the_9", "pancreper1", "perefrazz", "ponfertato", "roman.yagodin", "tibby", "un_logic", "vivatimperia", "wntrau", "Вoвa"}), - SPANISH("español", "es", Status.O_COMPLETE, new String[]{"KeyKai", "Kiroto", "Kohru", "airman12", "grayscales"}, new String[]{"2001sergiobr", "AdventurerKilly", "Alesxanderk", "Bryan092", "CorvosUtopy", "D0n.Kak0", "Dewstend", "Dyrran", "Enddox", "Fervoreking", "Illyatwo2", "Fuwn", "JPCHZ", "LastCry", "Marquezo_577_284", "NAVI1237", "No_se145", "STKmonoqui", "Sh4rkill3r", "Uri2523", "alfongad", "anauta", "benzarr410", "chepe567.jc", "ctrijueque", "damc0616", "desen90", "dhg121", "javifs", "jonismack1", "magmax", "rechebeltran", "tres.14159"}), + RUSSIAN("русский", "ru", Status.__UNREVIEW, new String[]{"AprilRain(Vadzim Navumaû)", "ConsideredHamster", "Dominowood371", "Inevielle", "apxwn", "yarikonline"}, new String[]{"5r", "AngryPotato", "AttHawk46", "BlueberryShortcake", "CatGirlSasha", "Enwviun", "HerrGotlieb", "HoloTheWise", "Ilbko", "JleHuBbluKoT", "KirStaLong", "MrXantar", "Nikets", "OneDuo", "Originalej0name", "Provitia", "Raymundo", "Roycce", "Shamahan", "Thomasg63", "XAutumn", "Ya6lo4ko", "chelikchelik", "dasfan123", "ifritdiezel", "katyp2005", "kirusyaga", "kptmx", "leondorus", "long_live_the_9", "pancreper1", "perefrazz", "ponfertato", "roman.yagodin", "tibby", "un_logic", "vivatimperia", "wntrau", "xenrun", "Вoвa"}), + SPANISH("español", "es", Status.O_COMPLETE, new String[]{"KeyKai", "Kiroto", "Kohru", "airman12", "grayscales"}, new String[]{"2001sergiobr", "AdventurerKilly", "Alesxanderk", "Bryan092", "CorvosUtopy", "D0n.Kak0", "Dewstend", "Dyrran", "Enddox", "Fervoreking", "Illyatwo2", "Fuwn", "JPCHZ", "LastCry", "Marquezo_577_284", "NAVI1237", "No_se145", "STKmonoqui", "Sh4rkill3r", "Uri2523", "alfongad", "alquimistamyl", "anauta", "benzarr410", "chepe567.jc", "ctrijueque", "damc0616", "desen90", "dhg121", "javifs", "jonismack1", "magmax", "rechebeltran", "saadhabibi077", "tres.14159"}), PORTUGUESE("português", "pt", Status.O_COMPLETE, new String[]{"NicholasPainek", "TDF2001", "matheus208"}, new String[]{"14NGiestas", "Aetheryll", "Andrew_px1", "Arthur_Mastriaga", "Bigode935", "Bionic64", "Chacal.Ex", "ChainedFreaK", "DAVICCOSTA", "DRACOnicus", "Derik", "DredgenVale", "ElefanteFome", "Helen0903", "JST", "Kotaroo05", "MadHorus", "Maria_João", "MarkusCoisa", "Matie", "Ninguem.EXE", "OtávioMoraes", "PingasOwner", "Piraldo", "Sr.BaconDelicioso", "Tete_Teli", "Tio_P_(Krampus)", "Zukkine", "ancientorange", "danypr23", "denis.gnl", "efverick", "gBiazon", "ismael.henriques12", "juniorsilve33", "mfcord", "nattlegal", "owenreilly", "phobos445", "rafazago", "renan408", "try31"}), GERMAN("deutsch", "de", Status.O_COMPLETE, new String[]{"Dallukas", "KrystalCroft", "Wuzzy", "Zap0", "apxwn", "bernhardreiter", "davedude"}, new String[]{"2711chrissi", "Abracadabra", "Anaklysmos", "Ceeee", "DarkPixel", "David.transifex", "EmilKevinManuel", "ErichME", "Faquarl", "JorahEtLabora", "LenzB", "MacMoff", "Micksha", "Niseko", "Ordoviz", "Sarius", "Shtynow", "SirEddi", "Sorpl3x", "SurmanPP", "SwissQ", "ThunfischGott", "Timo_S", "Topicranger", "azrdev", "carrageen", "dome.scheidler", "galactictrans", "gekko303", "jeinzi", "johannes.schobel", "karoshi42", "koryphea", "luciocarreras", "mklr", "niemand", "oragothen", "razzifazzi0", "spixi", "tanjay", "unbekannterTyp", "wunst"}), FRENCH("français", "fr", Status.O_COMPLETE, new String[]{"Emether", "TheKappaDuWeb", "Weende_Bellet", "Xalofar", "canc42", "kultissim", "minikrob", "Lucasgstar"}, new String[]{"3raven", "Alsydis", "Anonyme48", "Axce", "Az_zahr", "Bastien72", "Basttee", "Coco_EC", "Dekadisk", "Draal", "Eragem", "Karnot", "L.E.V.", "Lama", "Le_Valla", "Leandre", "Louson", "Martin.Bellet", "Neopolitan", "NoGi", "Nyrnx", "Opidox", "Pandaman516", "Petit_Chat", "RomTheMareep", "RunningColours", "STPayoube", "Soeiz", "SpeagleZNT", "Teddywestside", "Tronche2Cake", "VRad", "Ygdrazil", "_nim_", "adamch", "adeb", "antoine9298", "clexanis", "eloiseflo", "fricht", "gdavid2", "go11um", "hydrasho", "jan.", "jazzzz", "levilbatard", "linterpreteur", "luffah", "maeltur70", "marmous", "mcbaba29000", "mluzarreta", "panopano", "solthaar", "speagle", "tkf_", "typhr80", "vavavoum", "whereisfelix", "willi3725", "zM_"}), JAPANESE("日本語", "ja", Status.O_COMPLETE, new String[]{"daingewuvzeevisiddfddd", "oz51199"}, new String[]{"Gosamaru", "NickZhrbin", "Otogiri", "Siraore_Rou", "amama", "grassedge", "kiyofumimanabe", "librada", "mocklike", "tomofumikitano"}), - CHI_TRAD("繁體中文","zh-hant", Status.__UNREVIEW, new String[]{"JZR", "p2635"}, new String[]{"Fishbone", "Ken4Ro", "Lstron", "Relrin167", "Sotis425", "Yichm", "Zoe096423", "arnolam", "jackymaxj", "redbrow", "shiba", "唐延諭"}), + CHI_TRAD("繁體中文","zh-hant", Status.__UNREVIEW, new String[]{"JZR", "p2635"}, new String[]{"DT227", "Fishbone", "Ken4Ro", "Lstron", "Relrin167", "Sotis425", "Yichm", "Zoe096423", "arnolam", "jackymaxj", "redbrow", "shiba", "唐延諭"}), POLISH("polski", "pl", Status.__UNREVIEW, new String[]{"Daniel Witański", "Deksippos", "MrKukurykpl", "chronon", "kuadziw", "szymex73"}, new String[]{"Akmetari", "AntiTime", "Boguc", "Chasseur", "Ciechu", "Darden", "DarkKnightComes", "DogeseleQ", "GRan0000", "Hammil", "I256I", "KarixDaii", "KrnąbrnyOlaf", "Lufix", "MJedi", "MrCommander", "Odiihinia", "Ostsee0912", "Peperos", "RolsoN", "Scharnvirk", "Serpens13", "Tangens", "VasteelXolotl", "Voyteq", "Wiiiiiii", "bobas10", "bogumilg", "bvader95", "dusakus", "elchudy", "jajkoswinka", "michaub", "mikolka9144", "ozziezombie", "szczoteczka22", "taki1", "transportowiec96"}), VIETNAMESE("tiếng việt","vi", Status.O_COMPLETE, new String[]{"Chuseko", "The_Hood", "nguyenanhkhoapythus"}, new String[]{"BlueSheepAlgodoo", "Phuc2401", "SpaceMetropolis", "Teh_boi", "Threyja", "Toluu", "bruhwut", "buicongminh_t63", "deadlevel13", "duongfg250", "h4ndy_c4ndy", "hniV", "khangxyz3g", "ngolamaz3", "nkhhu", "vdgiapp", "vtvinh24"}), - TURKISH("türkçe", "tr", Status.__UNREVIEW, new String[]{"LokiofMillenium", "Mustafa.10", "T3kin5iZ", "emrebnk", "gorkem_yılmaz"}, new String[]{"AGORAAA", "AchernarPrime", "AcuriousPotato", "BurningDaylight", "Helgon", "Koga", "Mehmet_Emin_21", "MuratEfeYilmaz", "OzanAlkan", "TR_Muhittin", "Talha_0_0", "TheMBDsvs", "Yllcare", "YORGANSIZMTAV", "ahmetbakicakir", "akkaya.mustafa", "alikeremozfidan", "alpekin98", "barankrky", "denizakalin", "eraysall402", "erdemozdemir98", "hasantahsin160", "immortalsamuraicn", "kayikyaki", "kempilbey", "melezorus34", "mitux", "mustafadoslu", "ryuga", "yasirckr85", "yukete"}), + TURKISH("türkçe", "tr", Status.__UNREVIEW, new String[]{"LokiofMillenium", "Mustafa.10", "T3kin5iZ", "emrebnk", "gorkem_yılmaz"}, new String[]{"AGORAAA", "AchernarPrime", "AcuriousPotato", "BurningDaylight", "Helgon", "Koga", "Mehmet_Emin_21", "MuratEfeYilmaz", "OzanAlkan", "TR_Muhittin", "Talha_0_0", "TheMBDsvs", "Yllcare", "YORGANSIZMTAV", "ahmetbakicakir", "akkaya.mustafa", "alikeremozfidan", "alpekin98", "barankrky", "denizakalin", "eraysall402", "erdemozdemir98", "hasantahsin160", "immortalsamuraicn", "kayikyaki", "kempilbey", "melezorus34", "mitux", "mustafadoslu", "ryuga", "superDpermn", "yasirckr85", "yukete"}), INDONESIAN("indonesia", "in", Status.__UNREVIEW, new String[]{"RF_4R4F1_03", "rakapratama"}, new String[]{"An_Ironstone", "Flasherx", "INDRA_SYAHPUTRA", "Izulhaaq", "Karanh", "M.Bintang.K", "PineFirebloom", "QiuQiuQi", "Taka31", "ZakyM313", "ZangieF347", "aachunemiku", "anagakenny24", "aryasatya_arifien", "atmorojo", "di9526985", "esprogarap", "hatsunnimiku", "icebearwand", "kirimaja", "lupar21", "luthfidzaky_ldzy", "mkakhsan301", "nicoalvito", "noeldycreator", "oolek", "wisnugafur"}), - ITALIAN("italiano", "it", Status.__UNREVIEW, new String[]{"MottledElm", "NeoAugustus", "bizzolino", "funnydwarf", "inkubo87"}, new String[]{"4est", "Danelix", "DaniMare", "Danzl", "Dj1234", "Eriliken", "Esse78", "Guiller124", "Hydr46605", "IoannesMaria", "LN_90", "Mat323", "Mister64", "Noostale", "PicchiSeba", "Tugamer89", "Tysal", "andrea049ita", "andreafaffo", "andrearubbino00", "cantarini", "carinellialessandro31", "dmytro.tokayev", "mamon68596", "mattiuw", "max1234ita", "maxifire32", "nessunluogo", "righi.a", "umby000", "unknown888", "valerio.bozzolan"}), + ITALIAN("italiano", "it", Status.__UNREVIEW, new String[]{"MottledElm", "NeoAugustus", "bizzolino", "funnydwarf", "inkubo87"}, new String[]{"4est", "Danelix", "DaniMare", "Danzl", "Dj1234", "Eriliken", "Esse78", "Guiller124", "Hydr46605", "IoannesMaria", "LN_90", "Mat323", "Mister64", "Noostale", "PicchiSeba", "Tugamer89", "Tysal", "andrea049ita", "andreafaffo", "andrearubbino00", "angelica.caruso", "cantarini", "carinellialessandro31", "dmytro.tokayev", "lorenzofrosi05", "mamon68596", "mattiuw", "max1234ita", "maxifire32", "nessunluogo", "righi.a", "umby000", "unknown888", "valerio.bozzolan"}), UKRANIAN("українська", "uk", Status.O_COMPLETE, new String[]{"Oster", "Snikewin", "zhushman00"}, new String[]{"AlexFenixUA", "Buster54", "Doodlinka", "Dotsent", "Lyttym", "MaxQuiet", "Mops", "Sadsaltan1", "TarasUA", "TheGuyBill", "Tomfire", "Volkov", "ZverWolf", "_bor_", "alexfenixva", "ddmaster3463", "filalex77", "holuydadko", "ingvarfed", "iu0v1", "jesternotricks", "lezzen", "myshokoleksander05", "oliolioxinfree", "qweez", "romanokurg", "so1der", "sterenkevicsasa", "vlisivka", "xojltoh", "yukete", "zhawty", "Мальвочка"}), CZECH("čeština", "cs", Status.__UNREVIEW, new String[]{"ObisMike", "novotnyvaclav"}, new String[]{"16cnovotny", "AshenShugar", "Autony", "Block_Vader", "Buba237", "JStrange", "Nerdiniel", "Patrik123", "RealBrofessor", "Thorn_123", "chuckjirka", "emteckos2", "kristanka"}), HUNGARIAN("magyar", "hu", Status.O_COMPLETE, new String[]{"dorheim", "summoner001", "szalaik"}, new String[]{"Csanevox", "Navetelen", "acszoltan111", "balazsszalab", "clarovani", "dhialub", "nanometer", "nardomaa", "savarall", "szemetvodor"}), - DUTCH("nederlands", "nl", Status.__UNREVIEW, new String[]{"AlbertBrand", "Mvharen"}, new String[]{"AvanLieshout", "Blokheck011", "Frankwert", "Gehenna", "Valco", "ZephyrZodiac", "link200023", "ojppe", "rmw", "th3f4llenh0rr0r"}), + DUTCH("nederlands", "nl", Status.O_COMPLETE, new String[]{"AlbertBrand", "Mvharen"}, new String[]{"AvanLieshout", "Blokheck011", "Frankwert", "Gehenna", "Valco", "ZephyrZodiac", "link200023", "ojppe", "rmw", "th3f4llenh0rr0r"}), SWEDISH("svenska", "sv", Status.__UNREVIEW, new String[]{"yeager"}, new String[]{"KeyB", "Moistmemesneverlie", "antonaut", "dotMavriQ", "leowitchhh"}), //FINNISH("suomi", "fi", Status.X_UNFIN, new String[]{"TenguKnight"}, new String[]{"Allugaattori10", "Dakkus", "Jaskas123", "MailBoxGod", "Oftox", "Sautari", "Tikkari"} ), GREEK("ελληνικά", "el", Status.X_UNFINISH, new String[]{"Aeonius", "Saxy"}, new String[]{"DU_Clouds", "VasKyr", "YiorgosH", "fr3sh", "nikolaoskelirakis", "stefboi", "toumbo", "val.exe"}), - BELARUSIAN("беларуская","be", Status.X_UNFINISH, new String[]{"AprilRain(Vadzim Navumaû)"}, new String[]{"4ebotar"}), + BELARUSIAN("беларуская","be", Status.X_UNFINISH, new String[]{"AprilRain(Vadzim Navumaû)"}, new String[]{"4ebotar", "Loentrin"}), //CATALAN("català", "ca", Status.X_UNFIN, new String[]{"Illyatwo2"}, new String[]{"Elosy", "n1ngu"}) //GALICIAN("galego", "gl", Status.X_UNFIN, new String[]{"xecarballido"}, null), //BASQUE("euskara", "eu", Status.X_UNFIN, new String[]{"Deathrevenge", "Osoitz"}, null), From a5111562982684b0ef08863845f6452c7162fd98 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 25 Sep 2025 12:33:33 -0400 Subject: [PATCH 55/62] v3.2.5: adjusted iOS dynamic island handling for buff indicator change --- .../scenes/GameScene.java | 15 +++--------- .../ios/IOSPlatformSupport.java | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index 15cdecacd..ffc77e832 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -374,17 +374,8 @@ public class GameScene extends PixelScene { int hpBarMaxWidth = 50; //default max width float buffBarTopRowMaxWidth = 55; //default max width if (largeInsetTop == 0 && insets.top > 0){ - //iOS's Dynamic island badly obstructs the first buff bar row - if (DeviceCompat.isiOS()){ - //TODO bad to hardcode and approximate this atm - // need to change this so iOS platformsupport returns cutout dimensions - // which would also help with detecting if the cutout is big enough to put into 2nd row =S - //note that the island is a bit smaller in terms of screen % on bigger iPhones - // we try to average that a bit here - float cutoutLeft = (Game.width*0.34f)/defaultZoom; - buffBarTopRowMaxWidth = Math.min(55, cutoutLeft - 32 + 3); - } else if (DeviceCompat.isAndroid()) { - //Android hole punches are of varying size and may obstruct various UI elements + //smaller non-notch cutouts are of varying size and may obstruct various UI elements + // some are small hole punches, some are huge dynamic islands RectF cutout = Game.platform.getDisplayCutout().scale(1f / defaultZoom); //if the cutout is positioned to obstruct the hero portrait in the status pane if (cutout.top < 30 @@ -417,8 +408,8 @@ public class GameScene extends PixelScene { && cutout.bottom > 11) { //subtract starting position, add a bit back to allow slight overlap buffBarTopRowMaxWidth = cutout.left - 32 + 3; + //TODO dynamic island can block 2nd row too =S } - } } float screentop = largeInsetTop; diff --git a/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java b/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java index 4debb6072..82ad8deef 100644 --- a/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java +++ b/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java @@ -58,6 +58,30 @@ public class IOSPlatformSupport extends PlatformSupport { return Gdx.graphics.getSafeInsetBottom() > 0; } + @Override + public RectF getDisplayCutout() { + int topInset = Gdx.graphics.getSafeInsetTop(); + + //older device with no cutout, or landscape (we ignore cutouts in this case) + if (topInset == 0){ + return new RectF(); + } + + //magic number BS for larger status bar caused by dynamic island + boolean hasDynamicIsland = topInset / Gdx.graphics.getBackBufferScale() >= 51; + + if (!hasDynamicIsland){ + //classic notch, just shrink for the oversized safe are and then return all top. + // this is inaccurate, as there's space left and right, but we don't care + return new RectF(0, 0, Game.width, topInset / 1.2f); + } else { + //we estimate dynamic island as being 130x390 px, 35px from top. + // this is mostly accurate, slightly oversized + RectF cutout = new RectF( Game.width/2 - 195, 35, Game.width/2 + 195, 165); + return cutout; + } + } + @Override public RectF getSafeInsets(int level) { RectF insets = super.getSafeInsets(INSET_ALL); From c9cb58bcf176da5a383de5a1ce5494455ae29383 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Fri, 26 Sep 2025 11:16:00 -0400 Subject: [PATCH 56/62] v3.2.5: further improved dynamic island handling --- .../scenes/GameScene.java | 32 ++++++++++++++++--- .../ui/BuffIndicator.java | 17 +++++++--- .../shatteredpixeldungeon/ui/StatusPane.java | 12 +++++-- .../ios/IOSPlatformSupport.java | 13 ++++++-- 4 files changed, 58 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index ffc77e832..1d5f31298 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -372,7 +372,9 @@ public class GameScene extends PixelScene { float heroPaneExtraWidth = insets.left; float menuBarMaxLeft = uiCamera.width-insets.right-MenuPane.WIDTH; int hpBarMaxWidth = 50; //default max width - float buffBarTopRowMaxWidth = 55; //default max width + float[] buffBarRowLimits = new float[9]; + float[] buffBarRowAdjusts = new float[9]; + if (largeInsetTop == 0 && insets.top > 0){ //smaller non-notch cutouts are of varying size and may obstruct various UI elements // some are small hole punches, some are huge dynamic islands @@ -406,9 +408,21 @@ public class GameScene extends PixelScene { && cutout.top < 10 && cutout.right > 32 && cutout.bottom > 11) { - //subtract starting position, add a bit back to allow slight overlap - buffBarTopRowMaxWidth = cutout.left - 32 + 3; - //TODO dynamic island can block 2nd row too =S + int i = 1; + int rowTop = 11; + //in most cases this just obstructs one row, but dynamic island can block more =S + while (cutout.bottom > rowTop){ + if (i == 1 || cutout.bottom > rowTop+2 ) { //always shorten first row + //subtract starting position, add a bit back to allow slight overlap + buffBarRowLimits[i] = cutout.left - 32 + 3; + } else { + //if row is only slightly cut off, lower it instead of limiting width + buffBarRowAdjusts[i] = cutout.bottom - rowTop + 1; + rowTop += buffBarRowAdjusts[i]; + } + i++; + rowTop += 8; + } } } @@ -438,7 +452,8 @@ public class GameScene extends PixelScene { status.camera = uiCamera; StatusPane.heroPaneExtraWidth = heroPaneExtraWidth; StatusPane.hpBarMaxWidth = hpBarMaxWidth; - StatusPane.buffBarTopRowMaxWidth = buffBarTopRowMaxWidth; + StatusPane.buffBarRowMaxWidths = buffBarRowLimits; + StatusPane.buffBarRowAdjusts = buffBarRowAdjusts; status.setRect(insets.left, uiSize > 0 ? uiCamera.height-39-insets.bottom : screentop, uiCamera.width - insets.left - insets.right, 0 ); add(status); @@ -455,6 +470,13 @@ public class GameScene extends PixelScene { boss = new BossHealthBar(); boss.camera = uiCamera; boss.setPos( (uiCamera.width - boss.width())/2, screentop + (landscape() ? 7 : 26)); + if (buffBarRowLimits[2] != 0){ + //if we potentially have a 3rd buff bar row, lower by 7px + boss.setPos(boss.left(), boss.top() + 7); + } else if (buffBarRowAdjusts[2] != 0){ + // + boss.setPos(boss.left(), boss.top() + buffBarRowAdjusts[2]); + } add(boss); resume = new ResumeIndicator(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java index 52149eccf..3c61c99ac 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java @@ -149,7 +149,10 @@ public class BuffIndicator extends Component { private boolean large = false; - public float firstRowWidth = -1; + //in some cases we want to limit some rows but not all by just reducing width + public float[] rowWidthLimits = new float[9]; //0 = no limit + //sometimes we also need to slightly lower a row, to avoid having to cut off width + public float[] rowHeightAdjusts = new float[9]; //0 = default adjust of 1 public BuffIndicator( Char ch, boolean large ) { super(); @@ -231,6 +234,7 @@ public class BuffIndicator extends Component { //layout int row = 1; + float rowTop = 0; int pos = 0; float lastIconRight = 0; int total = 0; @@ -241,18 +245,21 @@ public class BuffIndicator extends Component { } icon.visible = true; + //offset is needed to handle adjusting oversized click boxes on multiple rows icon.topOffset = (row > 1 && !large) ? -1 : 0; icon.updateIcon(); //button areas are slightly oversized, especially on small buttons - icon.setRect(x + pos * (size + 1), y + (row-1)*(size+1)-icon.topOffset, size + 1, size + (large ? 0 : 5)); + icon.setRect(x + pos * (size + 1), y + rowTop-icon.topOffset, size + 1, size + (large ? 0 : 5)); PixelScene.align(icon); pos++; lastIconRight = icon.right()-1; - if ((row+1)*(size+1) <= height - && (pos * (size + 1) + size > width || (row == 1 && firstRowWidth != -1 && pos * (size + 1) + size > firstRowWidth))){ + //if we're out of overall width but have more height, or this row has hits its limit + if ((rowTop+2*size+2 <= height && (pos * (size + 1) + size > width)) + || (rowWidthLimits[row] != 0 && pos * (size + 1) + size > rowWidthLimits[row])){ row++; + rowTop += size+1 + rowHeightAdjusts[row]; pos = 0; } total++; @@ -265,7 +272,7 @@ public class BuffIndicator extends Component { if (excessWidth > 0) { //if multiple rows, only compress last row ArrayList buttons = new ArrayList<>(); - float lastRowY = PixelScene.align(y + (row-1)*(size+1)); + float lastRowY = PixelScene.align(y + rowTop); int i = 1; for (BuffButton button : buffButtons.values()){ if (i > maxBuffs){ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java index fd0af2094..49ca6b367 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/StatusPane.java @@ -83,8 +83,9 @@ public class StatusPane extends Component { //potentially shrinks and/or repositions the hp bar to avoid some cutouts public static int hpBarMaxWidth = 50; private Image hpCutout; - //potentially cuts off the top row of the the buff indicator to avoid some cutouts - public static float buffBarTopRowMaxWidth = 50; + //potentially adjusts the row(s) of the the buff indicator to avoid some cutouts + public static float[] buffBarRowMaxWidths; + public static float[] buffBarRowAdjusts; public StatusPane( boolean large ){ super(); @@ -264,7 +265,12 @@ public class StatusPane extends Component { heroInfoOnBar.setRect(heroInfo.right(), y, 50, 9); - buffs.firstRowWidth = buffBarTopRowMaxWidth; + if (buffBarRowMaxWidths != null){ + buffs.rowWidthLimits = buffBarRowMaxWidths; + } + if (buffBarRowAdjusts != null){ + buffs.rowHeightAdjusts = buffBarRowAdjusts; + } buffs.setRect( x + heroPaneWidth + 1, y + 8, 55, 16 ); busy.x = x + 1; diff --git a/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java b/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java index 82ad8deef..a377a6fa3 100644 --- a/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java +++ b/ios/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ios/IOSPlatformSupport.java @@ -36,7 +36,6 @@ import com.watabou.utils.PlatformSupport; import com.watabou.utils.RectF; import org.robovm.apple.audiotoolbox.AudioServices; -import org.robovm.apple.coregraphics.CGRect; import org.robovm.apple.systemconfiguration.SCNetworkReachability; import org.robovm.apple.systemconfiguration.SCNetworkReachabilityFlags; import org.robovm.apple.uikit.UIApplication; @@ -75,9 +74,17 @@ public class IOSPlatformSupport extends PlatformSupport { // this is inaccurate, as there's space left and right, but we don't care return new RectF(0, 0, Game.width, topInset / 1.2f); } else { - //we estimate dynamic island as being 130x390 px, 35px from top. + //we estimate dynamic island as being 390x120 px, 40px from top. // this is mostly accurate, slightly oversized - RectF cutout = new RectF( Game.width/2 - 195, 35, Game.width/2 + 195, 165); + RectF cutout = new RectF( Game.width/2 - 195, 40, Game.width/2 + 195, 160); + + //iPhone air specifically has its island a bit lower + // so we check for its machine string and also simulator with same width + String machineString = HWMachine.getMachineString(); + if (machineString.equals("iPhone18,4") + || (machineString.equals("arm64") && Game.width == 1260)){ + cutout.shift(0, 15); + } return cutout; } } From 5e419e0575fbf92c4277b97b748e86cf3c13adfd Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Fri, 26 Sep 2025 11:32:48 -0400 Subject: [PATCH 57/62] v3.2.5: updated changelog, version, and TLs for v3.2.5 release! --- build.gradle | 4 +- .../messages/actors/actors_es.properties | 2 +- .../assets/messages/items/items_es.properties | 2 +- .../messages/journal/journal_cs.properties | 24 ++--- .../messages/levels/levels_vi.properties | 4 +- .../messages/Languages.java | 2 +- .../scenes/WelcomeScene.java | 2 +- .../ui/changelist/v3_X_Changes.java | 93 ++++++++++++------- 8 files changed, 78 insertions(+), 55 deletions(-) diff --git a/build.gradle b/build.gradle index 40b94d1c6..9ffaea973 100644 --- a/build.gradle +++ b/build.gradle @@ -14,8 +14,8 @@ allprojects { appName = 'Shattered Pixel Dungeon' appPackageName = 'com.shatteredpixel.shatteredpixeldungeon' - appVersionCode = 875 - appVersionName = '3.2.4' + appVersionCode = 876 + appVersionName = '3.2.5' appJavaCompatibility = JavaVersion.VERSION_11 diff --git a/core/src/main/assets/messages/actors/actors_es.properties b/core/src/main/assets/messages/actors/actors_es.properties index a2f12a69e..6e644e8cd 100644 --- a/core/src/main/assets/messages/actors/actors_es.properties +++ b/core/src/main/assets/messages/actors/actors_es.properties @@ -922,7 +922,7 @@ actors.hero.talent.improvised_projectiles.title=Proyectil improvisado actors.hero.talent.improvised_projectiles.desc=_+1:_ El Guerrero puede cegar a un enemigo por _2 turnos_ lanzándole cualquier ítem que no sea un arma arrojadiza. Tiene un tiempo de recarga de 50 turnos.\n\n_+2:_ El guerrero puede cegar a un enemigo por _3 turnos_ lanzándoles cualquier ítem que no sea un arma arrojadiza. Tiene un tiempo de recarga de 50 turnos. actors.hero.talent.hold_fast.title=firmeza -actors.hero.talent.hold_fast.desc=_+1:_ Cuando el Guerrero espera, gana _1-2 de armadura_ y reduce en _50%_ la pérdida de los beneficios de combo y escudo hasta que se mueva.\n\n_+2:_ Cuando el Guerrero espera, gana _2-4 de armadura_ y reduce en _75%_ la pérdida de los beneficios de combo y escudo hasta que se mueva.\n\n_+3:_ Cuando el Guerrero espera, gana _3-6 de armadura_ y reduce en _100%_ la pérdida de los beneficios de combo y escudo hasta que se mueva. +actors.hero.talent.hold_fast.desc=_+1:_ Cuando el Guerrero espera, gana _1-2 de armadura_ y reduce en _50%_ la pérdida de combo y blindaje hasta que se mueva.\n\n_+2:_ Cuando el Guerrero espera, gana _2-4 de armadura_ y reduce en _75%_ la pérdida de combo y blindaje hasta que se mueva.\n\n_+3:_ Cuando el Guerrero espera, gana _3-6 de armadura_ y reduce en _100%_ la pérdida de combo y blindaje hasta que se mueva. actors.hero.talent.strongman.title=forzudo actors.hero.talent.strongman.desc=_+1:_ La fuerza del Guerrero _aumenta un 8%_, redondeado hacia abajo.\n\n_+2:_ La fuerza del Guerrero _aumenta un 13%_, redondeado hacia abajo.\n\n_+3:_ La fuerza del Guerrero _aumenta un 18%_, redondeado hacia abajo. diff --git a/core/src/main/assets/messages/items/items_es.properties b/core/src/main/assets/messages/items/items_es.properties index cceb68f90..0fdb27ff7 100644 --- a/core/src/main/assets/messages/items/items_es.properties +++ b/core/src/main/assets/messages/items/items_es.properties @@ -2180,7 +2180,7 @@ items.weapon.missiles.missileweapon.stats_known=Este conjunto de armas arrojadiz items.weapon.missiles.missileweapon.stats_unknown=Tipicamente este conjunto de armas arrojadizas de _tier-%1$d_ causaría _%2$d-%3$d de daño_ y requiere _%4$d de fuerza_ para ser usado adecuadamente. items.weapon.missiles.missileweapon.stats_desc= items.weapon.missiles.missileweapon.probably_too_heavy=Probablemente esta arma sea demasiado pesada para ti. -items.weapon.missiles.missileweapon.distance=Las armas de alcance son más precisas a distancia y menos certeras cuerpo a cuerpo. +items.weapon.missiles.missileweapon.distance=Las armas arrojadizas son más precisas a distancia y menos certeras cuerpo a cuerpo. items.weapon.missiles.missileweapon.durability=Las armas arrojadizas se desgastarán y se romperán a medida que se usen. items.weapon.missiles.missileweapon.uses_left=Este conjunto de armas arrojadizas tiene _%d/%d_ usos restantes antes de que una se rompa. items.weapon.missiles.missileweapon.unlimited_uses=Este conjunto es de tan alta calidad que durará efectivamente para siempre. diff --git a/core/src/main/assets/messages/journal/journal_cs.properties b/core/src/main/assets/messages/journal/journal_cs.properties index 989e353ab..9af202a96 100644 --- a/core/src/main/assets/messages/journal/journal_cs.properties +++ b/core/src/main/assets/messages/journal/journal_cs.properties @@ -43,7 +43,7 @@ journal.document.adventurers_guide.surprise_attacks.body=Ani ti nejobratnější journal.document.adventurers_guide.identifying.title=Identifikace předmětů journal.document.adventurers_guide.identifying.body=Barvy lektvarů a symboly na svitcích jsou jiné v každém podzemí. Neidentifikované vybavení může být vylepšené nebo okouzlené, pokud máš štěstí, ale může být také prokleté!\n\nSvitky identifikace, vylepšení a odstranění prokletí jsou velmi užitečné, pokud chceš snížit riziko používání neidentifikovaného vybavení.\n\n(Seznam všech identifikovaných předmětů můžeeš najít v záložce předmětů ve své příručce) journal.document.adventurers_guide.food.title=Řešení hladu -journal.document.adventurers_guide.food.body=Efektivní dávkování jídla je jednen z nejlepších způsobů, jak zlepšit své šance na přežití. Zkus brát zdraví a hlad jako zdroje, které je nutné spravovat, ne udržovat vždy plné.\n\nPokud neumíráš hlady, budeš si pomalu regenerovat zdraví. Pokud se najíš na plném zdraví, přijde tato regenerace nazmar.\n\nPokud budeš své jídlo rozvrhovat podle toho, jak jsi na tom se zdravím, měly by ti zásoby vydržet mnohem déle. +journal.document.adventurers_guide.food.body=Efektivní dávkování jídla je jeden z nejlepších způsobů, jak zlepšit své šance na přežití. Zkus brát zdraví a hlad jako zdroje, které je nutné spravovat, ne udržovat vždy plné.\n\nPokud neumíráš hlady, budeš si pomalu regenerovat zdraví. Pokud se najíš na plném zdraví, přijde tato regenerace nazmar.\n\nPokud budeš své jídlo rozvrhovat podle toho, jak jsi na tom se zdravím, měly by ti zásoby vydržet mnohem déle. journal.document.adventurers_guide.alchemy.title=Alchymie a Doplňky journal.document.adventurers_guide.alchemy.body=Pokud neshledáš některý jednorázový předmět užitečným, můžeš jej použít jako surovinu v alchymickém kotlíku! Předměty lze použít v několika konkrétních receptech, nebo je lze rozložit na všestrannou alchymickou energii. Rozložení lektvarů nebo svitků na energii je navíc také identifikuje!\n\nDoplňky jsou jedinou součástí vybavení, kterou lze vyrobit prostřednictvím alchymie. Mohou poskytnout řadu různých užitečných efektů a lze je vyrobit z hrstky alchymické energie a magického katalyzátoru. Doplňky lze vylepšit dodáním více alchymické energie, čímž se jejich účinek zesílí.\n\n(První alchymický kotlík lze najít v 3. nebo 4. patře kobky. Poblíž kotlíků můžeš také najít stránky alchymické příručky.) journal.document.adventurers_guide.dieing.title=Zvládání porážky @@ -65,7 +65,7 @@ journal.document.adventurers_guide.magic.body=Magické útoky probíjejí zbroj journal.document.alchemy_guide.title=Příručka alchymie journal.document.alchemy_guide.potions.title=Úvod a Lektvary -journal.document.alchemy_guide.potions.body=Vítejte u Praktických Aplikací Alchymie! Tato kniha obsahuje recepty a návody, jak vyrábět předměty v alchymickém kotlíku.\n\nZačneme tím nejikoničtějším receptem alchymie: Lektvary!\n\nVlož do kotlíku tři semínka pro uvaření lektvaru. Každé semínko má svůj odpovídající lektvar, a uvařený lektvar může být ovlivněn některým z vložených semínek. Použití více semínek stejného druhu tuto šanci zvyšuje. +journal.document.alchemy_guide.potions.body=Vítejte u Praktických Aplikací Alchymie! Tato kniha obsahuje recepty a návody, jak vyrábět předměty v alchymickém kotlíku.\n\nZačneme tím nejikoničtějším receptem alchymie: Lektvary!\n\nVlož do kotlíku tři semínka pro uvaření lektvaru. Každé semínko má svůj odpovídající lektvar a uvařený lektvar může být ovlivněn některým z vložených semínek. Použití více semínek stejného druhu tuto šanci zvyšuje. journal.document.alchemy_guide.stones.title=Tvorba runových kamenů journal.document.alchemy_guide.stones.body=Vhození svitku do alchymického kotlíku rozloží jeho magii do dvou kamenů v kotli. Tím vzniknou runové kameny a svitek se identifikuje! journal.document.alchemy_guide.energy_food.title=Energie a jídlo @@ -77,7 +77,7 @@ journal.document.alchemy_guide.exotic_scrolls.body=Vzácné svitky lze připrzav journal.document.alchemy_guide.bombs.title=Vylepšené bomby journal.document.alchemy_guide.bombs.body=Obyčejná černá prachová bomba může být smíchána s konkrétním předmětem pro vytvoření vylepšené bomby. journal.document.alchemy_guide.weapons.title=Posilování zbraní -journal.document.alchemy_guide.weapons.body=Některé lehčí nebo kouzelné zbraně mohou být v alchymii užitečné!\n\nKaždou vrhací zbraň lze rozložit na takové množství tekutého kovu, které by opravilo jinou zbraň stejného stupně a úrovně. Rozložení sady vrhacích zbraní zničí celou sadu, dokonce i když není celá přítomná.\n\nHůlka může být rozčarována na toolik kouzelné pryskyřice, aby bylo možné s ní vylepšit dvě hůlky stejné úrovně, ovšem do maximální úrovně +3. +journal.document.alchemy_guide.weapons.body=Některé lehčí nebo kouzelné zbraně mohou být v alchymii užitečné!\n\nKaždou vrhací zbraň lze rozložit na takové množství tekutého kovu, které by opravilo jinou zbraň stejného stupně a úrovně. Rozložení sady vrhacích zbraní zničí celou sadu, dokonce i když není celá přítomná.\n\nHůlka může být rozčarována na tolik kouzelné pryskyřice, aby bylo možné s ní vylepšit dvě hůlky stejné úrovně, ovšem do maximální úrovně +3. journal.document.alchemy_guide.brews_elixirs.title=Směsi a elixíry journal.document.alchemy_guide.brews_elixirs.body=Směsi a elixíry jsou pokročilé lektvary, které poskytují variantu různých efektů a lze je obvykle použít jen jednou. journal.document.alchemy_guide.spells.title=Kouzla @@ -125,7 +125,7 @@ journal.document.prison_warden.mines.body=53. zima, 363\n\nDnes dorazila skupina journal.document.prison_warden.rotberry.title=Rostlina hnilůvka journal.document.prison_warden.rotberry.body=23. podzim, 363\n\nDnes jsem dostala milý dárek od Felixe. Je to malý červený keřík, prý se mu říká 'Hnilůvka'.\n\nZmiňovala jsem se mu, jak je to tu ponuré, a vypadá to, že mě poslouchal. Zmiňoval, že tahle rostlina ve skutečnosti nesnáší světlo a vodu, takže prý stačí zhruba jednou měsíčně zastřihávat listy. To stříhání ale asi bude důležité, zmiňoval to ve svém dopise hned několikrát.\n\nSamozřejmě, že Felix nikdy nic nedělá zadarmo. Tvrdil, že semínka téhle věci jsou úžasné k výrobě hůlek, takže mu jich pár dlužím, až vyrostou.\n- Smithová journal.document.prison_warden.no_support.title=Bez podpory -journal.document.prison_warden.no_support.body=11. jaro, 364\n\nCo si sakra město myslí? Po urgentní žádosti o pomoc jsem nedostala nic, ani prázdný dopis s omluvou jako obvykle, když mi zamítnou žádost.\n\nMezitím to tu s chovanci vypadá stále hůř, a i někteří ze strážných začali dělat potíže. To budou prostě čekat, než se zto zhorší natolik, že tady budeme mít vzpouru!?\n\nAlespoň Thomas je zatím spolehlivý jako vždy. Jeho pomoc s organizací je neuvěřitelná, a jeho nápad uvést do provozu staré DM-100 je sice politováníhodný, ale nezbytný. Věřím, že tuhle situaci nakonec zvládneme, jen potřebuju nějakou podporu, zatraceně!\n- Smithová +journal.document.prison_warden.no_support.body=11. jaro, 364\n\nCo si sakra město myslí? Po urgentní žádosti o pomoc jsem nedostala nic, ani prázdný dopis s omluvou jako obvykle, když mi zamítnou žádost.\n\nMezitím to tu s chovanci vypadá stále hůř, a i někteří ze strážných začali dělat potíže. To budou prostě čekat, než se to zhorší natolik, že tady budeme mít vzpouru!?\n\nAlespoň Thomas je zatím spolehlivý jako vždy. Jeho pomoc s organizací je neuvěřitelná, a jeho nápad uvést do provozu staré DM-100 je sice politováníhodný, ale nezbytný. Věřím, že tuhle situaci nakonec zvládneme, jen potřebuju nějakou podporu, zatraceně!\n- Smithová journal.document.prison_warden.letter.title=Dopis Thomasovi journal.document.prison_warden.letter.body=Thomasi,\n\njsi můj dobrý přítel, takže ti udělám laskavost.\n\nAž dnes začneš svoji směnu, zamkni a zabezpeč Tenguovu celu, klíč schovej do nějakého výklenku a uteč. Nezáleží, jestli budou ostatní vězni bez dozoru, brzy se odtud stejně nikdo nedostane. Ten magor ale musí zůstat pod zámkem, kdyby utekl, nikdo neví, co by mohl udělat.\n\nNikomu to neříkej a nechoď mě prosím hledat. Kapitán opouští loď poslední.\n-Kiana @@ -142,31 +142,31 @@ journal.document.caves_explorer.city.body=21. léto, 308\n\nDneškem jsou to pr journal.document.caves_explorer.alive.title=Je to živé! journal.document.caves_explorer.alive.body=23. léto, 308\n\nJeden z trpasličích strojů se nějakým způsobem dal do pohybu! Jen jsme procházeli kolem, když se zničehonic nabil a málem rozdrtil dva členy skupiny svými velkými ocelovými pěstmi. Naštěstí jsem s sebou měl svou hůlku ničivých paprsků, stačilo pár dobře mířených ran a z té mašiny byla hromada šrotu.\n\nTo, co mě tíží, je fakt, že jsme neudělali nic, čím bychom ten stroj mohli vyprovokovat. Pochybuji, že by trpaslíci navrhli stroje takto agresivní, bylo to spíš, jako by nás ten stroj sám snažil přepadnout!\n\nAlespoň jsem svým společníkům mohl být projednou užitečný.\n- Archibald journal.document.caves_explorer.report.title=Konečné hlášení -journal.document.caves_explorer.report.body=28. léto, 308\n\nDnes dokončíme balení věcí a připravíme se k odchodu. Je to právě včas, několik členů expedice začalo mít děsivé noční můry po incidentu s agresivním strojem. Je to pravděpodobně únavou, ovšem jejich noční můry se zdají být podezřele podobné.\n\nSouhrně se dá prohlásit, že vrchní patra dolu jsou relativně bezpečná. Pokud bude někdy objeven způsob využití temného zlata, mohla by jeho těžba být výnosná. Velké otevřené prostory jsou vhodné pro městské konstrukční plány. Nižší patra dolu jsou nebezpečná a doporučuji se jim vyhnout.\n\nVšechno shrnu ve svém konečném hlášení během pár následujících dní.\n- Archibald +journal.document.caves_explorer.report.body=28. léto, 308\n\nDnes dokončíme balení věcí a připravíme se k odchodu. Je to právě včas. Několik členů expedice začalo mít děsivé noční můry po incidentu s agresivním strojem. Je to pravděpodobně únavou, ovšem jejich noční můry se zdají být podezřele podobné.\n\nSouhrně se dá prohlásit, že vrchní patra dolu jsou relativně bezpečná. Pokud bude někdy objeven způsob využití temného zlata, mohla by jeho těžba být výnosná. Velké otevřené prostory jsou vhodné pro městské konstrukční plány. Nižší patra dolu jsou nebezpečná a doporučuji se jim vyhnout.\n\nVšechno shrnu ve svém konečném hlášení během pár následujících dní.\n- Archibald journal.document.city_warlock.title=Čarodějův deník journal.document.city_warlock.discover_hint=Tento text můžeš najít ve specifické oblasti, ale až po nalezení všech předchozích textů v této sadě. journal.document.city_warlock.old_king.title=Král je mrtev -journal.document.city_warlock.old_king.body=Píše se 5. den 2. měsíce 33. roku věku magie. Pokud tento záznak čte někdo zvenku, je nejspíš něco kolem zimy 264. Mé jméno je Thymor Zahir a podle všech informací jsem poslední žijící člen trpasličího dvora.\n\nNáš král zemřel a nahradil ho jeden z mých kolegů, který zešílel svou mocí. Zbylí dvořané se mu podrobili, čímž ti hlupáci ztratili svou svobodnou vůli. Já jediný jsem to předvídal a utekl jsem, než byl rituál dokončen.\n\nVnitřní kruh sice padl, ale síla Nového Krále se stále nedostala ke každému. Musím vybudovat odpor jak rychle to jen půjde. Odmítám nechat naši přeslavnou civilizaci padnout do spárů toho šíleného megalomaniaka! +journal.document.city_warlock.old_king.body=Píše se 5. den 2. měsíce 33. roku věku magie. Pokud tento záznak čte někdo zvenku, je nejspíš něco kolem zimy 264. Mé jméno je Thymor Zahir a podle všech informací jsem poslední žijící člen trpasličího dvora.\n\nNáš Král zemřel a nahradil ho jeden z mých kolegů, který zešílel svou mocí. Zbylí dvořané se mu podrobili, čímž ti hlupáci ztratili svou svobodnou vůli. Já jediný jsem to předvídal a utekl jsem, než byl rituál dokončen.\n\nVnitřní kruh sice padl, ale síla Nového Krále se stále nedostala ke každému. Musím vybudovat odpor jak rychle to jen půjde. Odmítám nechat naši přeslavnou civilizaci padnout do spárů toho šíleného megalomaniaka! journal.document.city_warlock.resistance.title=Odpor -journal.document.city_warlock.resistance.body=Novinky se šíří rychle. Uplynule jen pár dní a už se mi podařilo vybudovat malu armádu trpaslíků věrných Starému Králi. Málo z nich má zkušenosti s magií, ale téměř celý řád bojových mnichů je na naší straně. Naše síly by měly být víc než vyrovnané jednomu šílenci a jeho dvoru plnému otroků.\n\nNový král se mezití schoval do vnitřních komnat našeho města. Nemám pochybnosti o tom, že už vynaložil většinu své moci a doufá, že se bude moct zotavit, než narazí na další odpor.\n\nBěhem pár hodin zaútočíme. S trochou štěstí dokážeme sestavit prozatímní koncil a navrátit našemu městu jeho stabilitu než skončí noc. +journal.document.city_warlock.resistance.body=Novinky se šíří rychle. Uplynulo jen pár dní a už se mi podařilo vybudovat malou armádu trpaslíků věrných Starému Králi. Málo z nich má zkušenosti s magií, ale téměř celý řád bojových mnichů je na naší straně. Naše síly by měly být víc než vyrovnané jednomu šílenci a jeho dvoru plnému otroků.\n\nNový Král se mezitím schoval do vnitřních komnat našeho města. Nemám pochybnosti o tom, že už vynaložil většinu své moci a doufá, že se bude moct zotavit, než narazí na další odpor.\n\nBěhem pár hodin zaútočíme. S trochou štěstí dokážeme sestavit prozatímní koncil a navrátit našemu městu jeho stabilitu než skončí noc. journal.document.city_warlock.failure.title=Selhání journal.document.city_warlock.failure.body=Zdá se, že to já jsem hlupák. Myslel jsem, že bude Nový Král potřebovat, aby se mu dvořané rozhodli zavázat z vlastní vůle, ale teď již vidím, že si dokáže podrobit i ty, kteří mu vzdorují.\n\nSlepě jsem navedl naše největší síly přímo před jeho brány, jen aby z nich mohl osobně udělat své otroky. Nyní vlny jeho nekrotické síly proplouvají naším městem a většinu ostatních okamžitě mění v jeho služebníky.\n\nNěkolik málo, kterým zbyla svobodná vůle, prchá z města. Já jsem se rozhodl zůstat a hledat nějakou skulinku. Se svou magickou mocí bych měl dokázat zůstat skrytý a v bezpečí na nějakou dobu. journal.document.city_warlock.more_powerful.title=Mocnější -journal.document.city_warlock.more_powerful.body=Držet pojetí o čase je těžší a těžší, ale od mého posledního zápisu uplynul zhruba týden. Naše civilizace padla. Brány jsou zavřeny, všechny funkce naší společnosti pohasly a prázdné schránky trpaslíků bloudí našimi síněmi.\n\nBěhem toho všeho získal nový král nějakým způsobem ještě větší moc. Síla jeho vůle každým dnem roste, ale také se mění. Neumím to popsat, ale připadá mi to, jako kdyby to už vůbec nebyl trpaslík.\n\nZačínám přijímat, že nejlepší, v co mohu doufat, je zdokumentovat tyto události. Zůstanu tu, jak dlouho to jen půjde, a až má vůle začne slábnout, vzdám se. +journal.document.city_warlock.more_powerful.body=Držet pojetí o čase je těžší a těžší, ale od mého posledního zápisu uplynul zhruba týden. Naše civilizace padla. Brány jsou zavřeny, všechny funkce naší společnosti pohasly a prázdné schránky trpaslíků bloudí našimi síněmi.\n\nBěhem toho všeho získal Nový Král nějakým způsobem ještě větší moc. Síla jeho vůle každým dnem roste, ale také se mění. Neumím to popsat, ale připadá mi to, jako kdyby to už vůbec nebyl trpaslík.\n\nZačínám přijímat, že nejlepší, v co mohu doufat, je zdokumentovat tyto události. Zůstanu tu, jak dlouho to jen půjde, a až má vůle začne slábnout, vzdám se. journal.document.city_warlock.new_power.title=Nová síla -journal.document.city_warlock.new_power.body=Co se tu děje? Síla, kterou vyzařuje nový král je opravdu jiná, než zpočátku, ale je tu ještě něco jiného. Tato nová moc zřejmě vyzařuje z vnitřních síní našeho města.\n\nJeště záhadnější je to, že aktivita ve svrchních patrech metropole se také zklidnila. Netuším, co se tam dole děje, ale zdá se, že tomu nový král věnuje veškerou svou pozornost.\n\nNávrat do vnitřních síní bude nebezpečný, ale musím zjistit, co tuhle změnu vyvolalo. Možná, že Nový Král přeci jenom má slabinu? +journal.document.city_warlock.new_power.body=Co se tu děje? Síla, kterou vyzařuje nový král je opravdu jiná, než zpočátku, ale je tu ještě něco jiného. Tato nová moc zřejmě vyzařuje z vnitřních síní našeho města.\n\nJeště záhadnější je to, že aktivita ve svrchních patrech metropole se také zklidnila. Netuším, co se tam dole děje, ale zdá se, že tomu Nový Král věnuje veškerou svou pozornost.\n\nNávrat do vnitřních síní bude nebezpečný, ale musím zjistit, co tuhle změnu vyvolalo. Možná, že Nový Král přeci jenom má slabinu? journal.document.city_warlock.seen_it.title=Viděl jsem to -journal.document.city_warlock.seen_it.body=Viděl jsem, co je tam dole, ale nedokážu to popsat. Moje ruce se neovladatelně třesou, když se snažím své myšlenky vyjádřit písmem.\n\nProč se tohle děje? Způsobil to nový král? Nedává to smysl. Možná to přilákalo jeho svévolné používání magické moci? Doufal jsem, že zachráním naši civilizaci, ale teď je zřejmé, že v sázce je osud celého světa.\n\nNajednou je král menší zlo. Nemám na vybranou, v zájmu vyššího dobra se vzdám. Prosím, veď mě, můj králi, použij mě jako nástroj k zastavení Yog-Dzewy! +journal.document.city_warlock.seen_it.body=Viděl jsem, co je tam dole, ale nedokážu to popsat. Moje ruce se neovladatelně třesou, když se snažím své myšlenky vyjádřit písmem.\n\nProč se tohle děje? Způsobil to Nový Král? Nedává to smysl. Možná to přilákalo jeho svévolné používání magické moci? Doufal jsem, že zachráním naši civilizaci, ale teď je zřejmé, že v sázce je osud celého světa.\n\nNajednou je král menší zlo. Nemám na vybranou, v zájmu vyššího dobra se vzdám. Prosím, veď mě, můj králi, použij mě jako nástroj k zastavení Yog-Dzewy! journal.document.halls_king.title=??? deník journal.document.halls_king.discover_hint=Tento text můžeš najít ve specifické oblasti, ale až po nalezení všech předchozích textů v této sadě. journal.document.halls_king.rejection.title=Odmítnutí -journal.document.halls_king.rejection.body=IMBECILOVÉ!\n\nPo 33 let naše království vzkvétalo díky magické technologii. Naučili jsme se vyvoválat duchy elementů a poodrobit je své vůli, ale najednou jsou další experimenty "moc nebezpečné".\n\nVím přesně, co se děje. Zamítnutí mých teorií nemá nic společného se zásluhami, ale s tím, kdo je předloží. Všichni se mi vysmívají za zády.\n\nAle toho už bylo dost! Je mi jedno, co si říkají, já prozkoumám nejtajnější kouty našeho vesmíru sám, a nechám si své nálezy jen pro sebe!\n- R. +journal.document.halls_king.rejection.body=IMBECILOVÉ!\n\nPo 33 let naše království vzkvétalo díky magické technologii. Naučili jsme se vyvoválat duchy elementů a podrobit je své vůli, ale najednou jsou další experimenty "moc nebezpečné".\n\nVím přesně, co se děje. Zamítnutí mých teorií nemá nic společného se zásluhami, ale s tím, kdo je předloží. Všichni se mi vysmívají za zády.\n\nAle toho už bylo dost! Je mi jedno, co si říkají, já prozkoumám nejtajnější kouty našeho vesmíru sám, a nechám si své nálezy jen pro sebe!\n- R. journal.document.halls_king.amulet.title=Amulet journal.document.halls_king.amulet.body=DOKÁZAL JSEM TO!\n\nNetušil jsem, co přesně najdu, ale to, co jsem nalezl, předčilo má nejdivočejší očekávání. Taková moc, jentak si ležící a čekající, až ji vezmu, je teď jenom moje!\n\nS tímhle mi nikdo z těch hlupáků nebude stát v cestě. Třesu se při pomyšlení, kolika způsoby je teď můžu všechny ponížit. Ale proč zůstávat jen u toho, mám dost síly, abych je všechny zničil, kdykoliv si umanu! To je možná trochu moc, ale nesmím se rozhodovat dlouho, jinak mě začnou podezírat.\n\nMyslím, že té obrovské moci budu říkat Amulet Yendoru!\n- R. journal.document.halls_king.ritual.title=Rituál -journal.document.halls_king.ritual.body=Thymor mě dnes veřejně oslovil a dožadoval se vysvětlení mého nového zdroje moci. Odbyl jsem ho nejlépe, jak jsem mohl, ale zase na sobě cítím palčivé pohledy zbylých členů koncilu.\n\nDoufal jsem, že si budu moct déle užívat toho ticha před bouří, ale na tom už nesejde. Rozhodl jsem se, co chci udělat. Prohlásím, že jsem svou moc získal skrze nový rituál, a nabídnu jeho provedení s jinými čaroději a s králem. Jakmile rituál skončí, králem budu já!\n\nThymor bude samozřejmě zase protestovat, ale s nabídkou takové moci pochybuji, že ho někdo bude poslouchat!\n\nVŠICHNI SE MI POKLONÍ!\n- Budoucí Král Trpaslíků +journal.document.halls_king.ritual.body=Thymor mě dnes veřejně oslovil a dožadoval se vysvětlení mého nového zdroje moci. Odbyl jsem ho nejlépe, jak jsem mohl, ale zase na sobě cítím palčivé pohledy zbylých členů koncilu.\n\nDoufal jsem, že si budu moct déle užívat toho ticha před bouří, ale na tom už nesejde. Rozhodl jsem se, co chci udělat. Prohlásím, že jsem svou moc získal skrze nový rituál, a nabídnu jeho provedení s jinými čaroději a s Králem. Jakmile rituál skončí, králem budu já!\n\nThymor bude samozřejmě zase protestovat, ale s nabídkou takové moci pochybuji, že ho někdo bude poslouchat!\n\nVŠICHNI SE MI POKLONÍ!\n- Budoucí Král Trpaslíků journal.document.halls_king.new_king.title=Nový Král journal.document.halls_king.new_king.body=JÁ JSEM KRÁL, AHAHAHAHAAA!\n\nProstě mě nechali to udělat! Skoro bez přesvědčování všichni souhlasili, abych s nimi "sdílel" svou moc skrze velký rituál. Během chvíle se změnili ze sboru překřikujících se hlupáků a můj nový dvůr tichých sluhů.\n\nJak jsem čekal, ten zbabělec Thymor utekl při první známce nebezpečí. Už teď cítím, jak se snaží zbudovat odpor. Myslím, že mu dovolím v tom pokračovat, aby mi mohl všechny svoje konsirátory dovést přímo před dveře!\n\nOčividně ke mně království také nemá zrovna respekt, myslím, že to budu také muset napravit.\n- Král Trpaslíků journal.document.halls_king.thing.title=Ta Věc diff --git a/core/src/main/assets/messages/levels/levels_vi.properties b/core/src/main/assets/messages/levels/levels_vi.properties index 757804c71..8eda0a131 100644 --- a/core/src/main/assets/messages/levels/levels_vi.properties +++ b/core/src/main/assets/messages/levels/levels_vi.properties @@ -143,7 +143,7 @@ levels.traps.trap.rankings_desc=Bị giết bởi: %s levels.traps.corrosiontrap.name=bẫy khí ăn mòn levels.traps.corrosiontrap.desc=Kích hoạt cái bẫy này sẽ làm một đám mây khí có tính axit chết người thoát ra trong khu vực xung quanh. -levels.traps.warpingtrap.name=bẫy bẻ cong +levels.traps.warpingtrap.name=bẫy di dời levels.traps.warpingtrap.desc=Cái bẫy này tương tự như một cái bẫy dịch chuyển tức thời, nhưng cũng sẽ khiến người hùng mất đi hiểu biết của họ về bố cục của tầng! levels.traps.weakeningtrap.name=bẫy suy yếu @@ -202,7 +202,7 @@ levels.hallslevel.region_deco_name=Đống đá vụn levels.hallslevel.region_deco_desc=Một mảng đá lớn, có vẻ như đã rơi ra từ trên trần hoặc một bức tường gần đó. -levels.level.hidden_trap=Một cái %s kích hoạt! +levels.level.hidden_trap=Một chiếc %s ẩn kích hoạt! levels.level.chasm_name=Hố sâu levels.level.floor_name=Sàn levels.level.grass_name=Cỏ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/messages/Languages.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/messages/Languages.java index e9d0545c7..1dba723b1 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/messages/Languages.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/messages/Languages.java @@ -40,7 +40,7 @@ public enum Languages { INDONESIAN("indonesia", "in", Status.__UNREVIEW, new String[]{"RF_4R4F1_03", "rakapratama"}, new String[]{"An_Ironstone", "Flasherx", "INDRA_SYAHPUTRA", "Izulhaaq", "Karanh", "M.Bintang.K", "PineFirebloom", "QiuQiuQi", "Taka31", "ZakyM313", "ZangieF347", "aachunemiku", "anagakenny24", "aryasatya_arifien", "atmorojo", "di9526985", "esprogarap", "hatsunnimiku", "icebearwand", "kirimaja", "lupar21", "luthfidzaky_ldzy", "mkakhsan301", "nicoalvito", "noeldycreator", "oolek", "wisnugafur"}), ITALIAN("italiano", "it", Status.__UNREVIEW, new String[]{"MottledElm", "NeoAugustus", "bizzolino", "funnydwarf", "inkubo87"}, new String[]{"4est", "Danelix", "DaniMare", "Danzl", "Dj1234", "Eriliken", "Esse78", "Guiller124", "Hydr46605", "IoannesMaria", "LN_90", "Mat323", "Mister64", "Noostale", "PicchiSeba", "Tugamer89", "Tysal", "andrea049ita", "andreafaffo", "andrearubbino00", "angelica.caruso", "cantarini", "carinellialessandro31", "dmytro.tokayev", "lorenzofrosi05", "mamon68596", "mattiuw", "max1234ita", "maxifire32", "nessunluogo", "righi.a", "umby000", "unknown888", "valerio.bozzolan"}), UKRANIAN("українська", "uk", Status.O_COMPLETE, new String[]{"Oster", "Snikewin", "zhushman00"}, new String[]{"AlexFenixUA", "Buster54", "Doodlinka", "Dotsent", "Lyttym", "MaxQuiet", "Mops", "Sadsaltan1", "TarasUA", "TheGuyBill", "Tomfire", "Volkov", "ZverWolf", "_bor_", "alexfenixva", "ddmaster3463", "filalex77", "holuydadko", "ingvarfed", "iu0v1", "jesternotricks", "lezzen", "myshokoleksander05", "oliolioxinfree", "qweez", "romanokurg", "so1der", "sterenkevicsasa", "vlisivka", "xojltoh", "yukete", "zhawty", "Мальвочка"}), - CZECH("čeština", "cs", Status.__UNREVIEW, new String[]{"ObisMike", "novotnyvaclav"}, new String[]{"16cnovotny", "AshenShugar", "Autony", "Block_Vader", "Buba237", "JStrange", "Nerdiniel", "Patrik123", "RealBrofessor", "Thorn_123", "chuckjirka", "emteckos2", "kristanka"}), + CZECH("čeština", "cs", Status.__UNREVIEW, new String[]{"ObisMike", "novotnyvaclav"}, new String[]{"16cnovotny", "AshenShugar", "Autony", "Block_Vader", "Buba237", "JStrange", "Nerdiniel", "Patrik123", "RealBrofessor", "Thorn_123", "chuckjirka", "emteckos2", "kristanka", "luhan.lukas"}), HUNGARIAN("magyar", "hu", Status.O_COMPLETE, new String[]{"dorheim", "summoner001", "szalaik"}, new String[]{"Csanevox", "Navetelen", "acszoltan111", "balazsszalab", "clarovani", "dhialub", "nanometer", "nardomaa", "savarall", "szemetvodor"}), DUTCH("nederlands", "nl", Status.O_COMPLETE, new String[]{"AlbertBrand", "Mvharen"}, new String[]{"AvanLieshout", "Blokheck011", "Frankwert", "Gehenna", "Valco", "ZephyrZodiac", "link200023", "ojppe", "rmw", "th3f4llenh0rr0r"}), SWEDISH("svenska", "sv", Status.__UNREVIEW, new String[]{"yeager"}, new String[]{"KeyB", "Moistmemesneverlie", "antonaut", "dotMavriQ", "leowitchhh"}), diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java index bff0bc387..8973ec3e3 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java @@ -207,7 +207,7 @@ public class WelcomeScene extends PixelScene { //TODO: change the messages here in accordance with the type of patch. message = Messages.get(this, "patch_intro"); message += "\n"; - //message += "\n" + Messages.get(this, "patch_balance"); + message += "\n" + Messages.get(this, "patch_balance"); message += "\n" + Messages.get(this, "patch_bugfixes"); message += "\n" + Messages.get(this, "patch_translations"); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java index 5623f989b..19e9fbd7d 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java @@ -86,6 +86,55 @@ public class v3_X_Changes { changes.hardlight(Window.TITLE_COLOR); changeInfos.add(changes); + changes = new ChangeInfo("v3.2.5", false, null); + changes.hardlight(Window.TITLE_COLOR); + changeInfos.add(changes); + + changes.addButton( new ChangeButton(Icons.get(Icons.SHPX), "Dev Commentary", + "...")); + + changes.addButton(new ChangeButton(Icons.get(Icons.DISPLAY), "Interface Changes", + "Two additions have been made to the game's UI:\n" + + "**-** The Boss health bar is now larger on full size UI, taking advantage of the bigger space.\n" + + "**-** The main menu now has a button to hide the interface, letting players look at the new background.\n" + + "\n" + + "Further tweaks have been made to the game's UI:\n" + + "**-** Health bars now display shielding in addition to HP, instead of on top of it.\n" + + "**-** The Hero status pane can now extend to the right to avoid cutouts on the top-left of the display, if there is room to do so.\n" + + "**-** Improved how the hero buff bar handles large cutouts like the dynamic island\n" + + "**-** Further increased the permissiveness of what cutouts the game tries to render around\n" + + "**-** Brightened the background of the game version indicator to make it look less like an empty health bar.\n" + + "**-** Fixed cases where Shattered would attempt to draw into cutouts when they weren't properly reported by the device.")); + + changes.addButton(new ChangeButton(Icons.get(Icons.PREFS), Messages.get(ChangesScene.class, "misc"), + "**-** Updated code libraries used to build Shattered's macOS distribution. This should fix the game taking unreasonably long to launch on some newer macs, but also means Shattered now requires at least macOS 10.12 Sierra, up from 10.10 Yosemite.\n" + + "\n" + + "**-** DM-300's rockfall attack now deals 6-12 damage (10-20 with badder bosses). This is for consistency with the rockfall attack done by the gnoll geomancer, and to prevent specific exploits where DM-300 couldn't damage hiding inorganic allies.\n" + + "\n" + + "**-** Levelling up the dried rose while the ghost hero is summoned now heals it for the same amount that the upgrade increases max HP.")); + + changes.addButton(new ChangeButton(new Image(Assets.Sprites.SPINNER, 144, 0, 16, 16), Messages.get(ChangesScene.class, "bugfixes"), + "Fixed the following bugs:\n" + + "**Caused by v3.2.X:**\n" + + "**-** Thrown weapon merging prioritizing properties on weapons already stuck to enemies, instead of incoming ones\n" + + "**-** Thrown weapons not being properly set to ID-ready by wells of awareness when hero has the shard of oblivion\n" + + "**-** Rats attacking the hero when they should be neutral in specific cases\n" + + "**-** Picking up throwing clubs and hammers taking time if done during time freeze\n" + + "**-** Various minor visual/textual errors\n" + + "**-** Various rare crash errors", + + "**Existed Prior to v3.2.0:**\n" + + "**-** Specific cases where bits of hidden walls could be seen through the fog of war\n" + + "**-** Specific errors with inter-floor teleports\n" + + "**-** DM-201s retaliating to corruption dmg\n" + + "**-** Crossbow's charged shot melee not triggering in some cases\n" + + "**-** Tab cycling not working correctly with inventory window\n" + + "**-** Golden bees not preferring potential targets affected by aggression debuff\n" + + "**-** Aggression debuff effect persisting on downed ghouls once they revive\n" + + "**-** Radiance stunning enemies are they are killed by it triggering illuminate\n" + + "**-** Prison guards being able to pull large characters into enclosed spaces\n" + + "**-** Various minor visual/textual errors")); + changes = new ChangeInfo("v3.2.4", false, null); changes.hardlight(Window.TITLE_COLOR); changeInfos.add(changes); @@ -105,7 +154,7 @@ public class v3_X_Changes { "Currently the background most strongly ties into the sewers region, but we have plans to add more variants in the future, one for each dungeon region!")); changes.addButton(new ChangeButton(Icons.get(Icons.DISPLAY_PORT), "Mobile Layout Changes", - "**Shattered now renders in true fullscreen on most mobile devices!**\n" + + "**Shattered's in-game screen now renders in true fullscreen on most mobile devices!**\n" + "\n" + "The status bar at the top of the in-game UI has been modified to work around small and medium sized hole punches and rounded corners on modern displays! This includes the dynamic island on modern iPhones. Thanks to these adjustments it's now possible for the UI to move up and for the game to display in true fullscreen during gameplay! Devices with larger cutouts like full-sized notches will unfortunately still have a dark bar on the top, as there isn't room for the UI.\n" + "\n" + @@ -121,52 +170,26 @@ public class v3_X_Changes { "**-** Improved how buff bar layout handles iOS dynamic island at smaller scale values.\n" + "**-** Renamed the mobile fullscreen setting to 'hide navigation bar' or 'hide gesture bar'")); - changes = new ChangeInfo("v3.2.3", false, null); + changes = new ChangeInfo("v3.2.2 & v3.2.3", false, null); changes.hardlight(Window.TITLE_COLOR); changeInfos.add(changes); changes.addButton( new ChangeButton(Icons.get(Icons.SHPX), "Dev Commentary", - "More tech improvements and modernizations for mobile users!\n" + - "\n" + - "This patch follows up on the previous one with some bug fixes, responses to feedback, and support for true edge-to-edge fullscreen on most game interfaces!\n" + + "These are the first of those 'technical improvements' patches I mentioned previously. Several changes have been made to modernize some aspects of Shattered Pixel Dungeon on Android, as well as a few smaller changes on iOS and internal changes on other platforms.\n" + "\n" + "I expect to be releasing one more major patch for v3.2 with further improvements, plus whatever else is needed for handling tech fixes.")); - changes.addButton(new ChangeButton(Icons.get(Icons.DISPLAY_PORT), "Mobile Layout Changes", - "**-** Shattered now renders in true edge-to-edge fullscreen on Android 9+ and iOS devices, with transparent navigation bars and rendering into display cutout regions!\n" + - "**-** All in-game interfaces have been adjusted to better handle true mobile fullscreen, including better insets on various UI elements at display corners.\n" + - "**-** Currently the in-game screen makes use of a solid dark bar at the top to handle display cutouts. This is temporary and that UI will be made true fullscreen soon for people with smaller display cutouts (e.g. hole punches).\n" + - "**-** Re-added some orientation control on Android in the form of a 'force landscape' setting. This setting may need to be removed in future Android versions.\n" + - "**-** Re-enabled 'fullscreen' setting on iOS (i.e. it can be turned off again), which now lightly raises UI elements to help prevent gesture mistaps")); - - changes.addButton(new ChangeButton(new Image(Assets.Sprites.SPINNER, 144, 0, 16, 16), Messages.get(ChangesScene.class, "bugfixes"), - "Fixed the following bugs:\n" + - "**Caused by v3.2.2:**\n" + - "**-** Windowed mode on desktop always defaulting to 1920x1080, instead of last window size\n" + - "**-** Various rare Android crashes caused by internal library updates\n" + - "**-** Fullscreen being incorrectly forced off on some older Android devices.")); - - changes = new ChangeInfo("v3.2.2", false, null); - changes.hardlight(Window.TITLE_COLOR); - changeInfos.add(changes); - - changes.addButton( new ChangeButton(Icons.get(Icons.SHPX), "Dev Commentary", - "Hey folks, this is the first of those 'technical improvements' patches I mentioned previously. Several changes have been made to modernize some aspects of Shattered Pixel Dungeon on Android, as well as a few smaller changes on iOS and internal changes on other platforms.\n" + - "\n" + - "One more change that I'm delaying for another patch is adjustments to screen layout logic to better support hole punches and small notches. No promises, but I'd like to let devices with smaller cutouts (like hole punches) play the game in true fullscreen. This may also extend to iOS users and the compact dynamic island.")); - changes.addButton(new ChangeButton(Icons.get(Icons.PREFS), Messages.get(ChangesScene.class, "misc"), - "**Android Changes:**\n" + - "**-** Removed landscape/portrait setting, game now uses system orientation instead. This is more consistent with the iOS version, and will be required in the future by Google anyway.\n" + + "**Mobile UI Changes:**\n" + + "**-** Shattered's menu screens now render in true edge-to-edge fullscreen on Android 9+ and iOS devices.\n" + + "**-** Android now defaults to device orientation instead of forced portrait, but there is a 'force landscape' setting.\n" + "**-** 'Fullscreen' (hiding the nav bar or gesture bar) now defaults to on, and is forced on if no nav or gesture bar is present.\n" + - "**-** Shattered Pixel Dungeon now requires Android 5.0+, up from 4.0+.\n" + - "**-** Fully removed Power Saver setting, which was already hidden for Android 4.4+ devices anyway.\n" + - "**-** Sharing Gameplay Data now requires Android 6.0+, up from 4.1+.\n" + - "**-** Updated various Google Play libraries.\n" + + "**-** Fully removed Android Power Saver setting, which was already hidden for Android 4.4+ devices anyway.\n" + "\n" + "**Other Changes:**\n" + - "**-** 'Fullscreen' (drawing over the home indicator) is now always on for iOS users, as iOS 26 is about to always auto-hide the home indicator anyway.\n" + "**-** Updated various internal code libraries.\n" + + "**-** Shattered Pixel Dungeon now requires Android 5.0+, up from 4.0+.\n" + + "**-** Sharing Gameplay Data now requires Android 6.0+, up from 4.1+.\n" + "**-** Desktop JAR build now requires Java 11+, up from 8+.\n" + "**-** Slightly adjusted the visuals at the end of the prison region.")); From 6d179184be53c034f025f566d7d30bf3319137d5 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 28 Sep 2025 10:50:48 -0400 Subject: [PATCH 58/62] v3.2.5: fixed a long-standing typo in burning desc --- core/src/main/assets/messages/actors/actors.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index fcc6cfa6a..443b100a3 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -138,7 +138,7 @@ actors.buffs.burning.heromsg=You catch fire! actors.buffs.burning.burnsup=%s burns up! actors.buffs.burning.ondeath=You burned to death... actors.buffs.burning.rankings_desc=Burned to Ash -actors.buffs.burning.desc=Few things are more distressing than being engulfed in flames.\n\nFire will deal damage every turn until it is put out by water or it expires. Fire can be extinquished by stepping into water, or from the splash of a shattering potion.\n\nAdditionally, the fire may ignite flammable terrain or items that it comes into contact with.\n\nTurns of burning remaining: %s. +actors.buffs.burning.desc=Few things are more distressing than being engulfed in flames.\n\nFire will deal damage every turn until it is put out by water or it expires. Fire can be extinguished by stepping into water, or from the splash of a shattering potion.\n\nAdditionally, the fire may ignite flammable terrain or items that it comes into contact with.\n\nTurns of burning remaining: %s. actors.buffs.championenemy.warn=You sense a deadly presence. actors.buffs.championenemy$blazing.name=blazing champion From 218e1216af4fd1bc31defed2c9baf5f115296406 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 28 Sep 2025 11:11:28 -0400 Subject: [PATCH 59/62] v3.2.5: added a few safety checks for various rare errors --- .../shatteredpixeldungeon/actors/hero/Hero.java | 2 +- .../shatteredpixeldungeon/actors/mobs/Mob.java | 2 +- .../shatteredpixeldungeon/scenes/GameScene.java | 11 ++++++----- .../shatteredpixeldungeon/ui/QuickSlotButton.java | 3 +++ 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java index aaacde2b9..935c563a3 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Hero.java @@ -607,7 +607,7 @@ public class Hero extends Char { Combo.ParryTracker parry = buff(Combo.ParryTracker.class); if (parry != null){ parry.parried = true; - if (buff(Combo.class).getComboCount() < 9 || pointsInTalent(Talent.ENHANCED_COMBO) < 2){ + if (buff(Combo.class) == null || buff(Combo.class).getComboCount() < 9 || pointsInTalent(Talent.ENHANCED_COMBO) < 2){ parry.detach(); } return Messages.get(Monk.class, "parried"); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java index e280c9785..208e1e2f9 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java @@ -502,7 +502,7 @@ public abstract class Mob extends Char { protected boolean getCloser( int target ) { - if (rooted || target == pos) { + if (rooted || target == pos || !Dungeon.level.insideMap(target)) { return false; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index 1d5f31298..6daba590b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -140,7 +140,6 @@ import com.watabou.noosa.audio.Sample; import com.watabou.noosa.particles.Emitter; import com.watabou.noosa.tweeners.Tweener; import com.watabou.utils.Callback; -import com.watabou.utils.DeviceCompat; import com.watabou.utils.GameMath; import com.watabou.utils.PlatformSupport; import com.watabou.utils.Point; @@ -1465,10 +1464,12 @@ public class GameScene extends PixelScene { @Override public void call() { //greater than 0 to account for negative values (which have the first bit set to 1) - if (color > 0 && color < 0x01000000) { - scene.fadeIn(0xFF000000 | color, lightmode); - } else { - scene.fadeIn(color, lightmode); + if (scene != null) { + if (color > 0 && color < 0x01000000) { + scene.fadeIn(0xFF000000 | color, lightmode); + } else { + scene.fadeIn(color, lightmode); + } } } }); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/QuickSlotButton.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/QuickSlotButton.java index 1f87066f5..a05ce6ef8 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/QuickSlotButton.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/QuickSlotButton.java @@ -349,6 +349,9 @@ public class QuickSlotButton extends Button { //FIXME: this is currently very expensive, should either optimize ballistica or this, or both public static int autoAim(Char target, Item item){ + if (Dungeon.hero == null){ + return -1; + } //first try to directly target if (item.targetingPos(Dungeon.hero, target.pos) == target.pos) { From b203e756211bc7c8635a49f24b48e0bbc4bee547 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sun, 28 Sep 2025 11:13:41 -0400 Subject: [PATCH 60/62] v3.2.5: fixed new fade button not accounting for insets --- .../shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java index ddd6fceb8..4b5b7a863 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java @@ -266,7 +266,7 @@ public class TitleScene extends PixelScene { }; btnFade.icon().originToCenter(); btnFade.icon().angle = 180f; - btnFade.setRect(btnAreaLeft + (buttonAreaWidth-16)/2, camera.main.height - 16, 16, 16); + btnFade.setRect(btnAreaLeft + (buttonAreaWidth-16)/2, camera.main.height - 16 - insets.bottom, 16, 16); add(btnFade); PointerArea fadeResetter = new PointerArea(0, 0, Camera.main.width, Camera.main.height){ From 4e1da695a25fe51ca1c7dd0a7bb2f6e98dba1a03 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Mon, 29 Sep 2025 10:51:28 -0400 Subject: [PATCH 61/62] v3.2.5: properly fixed bee AI re-aggression debuff --- .../actors/mobs/Bee.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bee.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bee.java index a173228f2..053ae7f76 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bee.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Bee.java @@ -152,7 +152,24 @@ public class Bee extends Mob { return (Char) Actor.findById(potHolder); //if the pot is on the ground - }else { + } else { + + //copypasta from regular mob logic for aggression with added limit for pot distance + if ((alignment == Alignment.ENEMY || buff(Amok.class) != null ) && state != PASSIVE && state != SLEEPING) { + if (enemy != null + && enemy.buff(StoneOfAggression.Aggression.class) != null + && Dungeon.level.distance(enemy.pos, potPos) <= 3){ + state = HUNTING; + return enemy; + } + for (Char ch : Actor.chars()) { + if (ch != this && fieldOfView[ch.pos] && Dungeon.level.distance(ch.pos, potPos) <= 3 + && ch.buff(StoneOfAggression.Aggression.class) != null) { + state = HUNTING; + return ch; + } + } + } //try to find a new enemy in these circumstances if (enemy == null || !enemy.isAlive() || !Actor.chars().contains(enemy) || state == WANDERING @@ -168,9 +185,7 @@ public class Bee extends Mob { && mob.alignment != Alignment.NEUTRAL && !mob.isInvulnerable(getClass()) && !(alignment == Alignment.ALLY && mob.alignment == Alignment.ALLY)) { - //prefers char affected by aggression - if (closest == null || mob.buff(StoneOfAggression.Aggression.class) != null - || Dungeon.level.distance(closest.pos, pos) > Dungeon.level.distance(mob.pos, pos)){ + if (closest == null || Dungeon.level.distance(closest.pos, pos) > Dungeon.level.distance(mob.pos, pos)){ closest = mob; } } From 510475319874ad56ada8f381acc0bbc13e570b36 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Mon, 29 Sep 2025 13:30:39 -0400 Subject: [PATCH 62/62] v3.2.5: updated version and changelog for amended v3.2.5 release --- build.gradle | 2 +- .../messages/actors/actors_vi.properties | 44 +++++++++---------- .../messages/actors/actors_zh-hant.properties | 10 ++--- .../assets/messages/items/items_vi.properties | 2 +- .../messages/items/items_zh-hant.properties | 4 +- .../messages/levels/levels_vi.properties | 4 +- .../assets/messages/misc/misc_eo.properties | 2 +- .../messages/plants/plants_vi.properties | 6 +-- .../ui/changelist/v3_X_Changes.java | 2 +- 9 files changed, 38 insertions(+), 38 deletions(-) diff --git a/build.gradle b/build.gradle index 9ffaea973..699deca0d 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ allprojects { appName = 'Shattered Pixel Dungeon' appPackageName = 'com.shatteredpixel.shatteredpixeldungeon' - appVersionCode = 876 + appVersionCode = 877 appVersionName = '3.2.5' appJavaCompatibility = JavaVersion.VERSION_11 diff --git a/core/src/main/assets/messages/actors/actors_vi.properties b/core/src/main/assets/messages/actors/actors_vi.properties index dd918b196..93d8a6914 100644 --- a/core/src/main/assets/messages/actors/actors_vi.properties +++ b/core/src/main/assets/messages/actors/actors_vi.properties @@ -68,19 +68,19 @@ actors.blobs.web.desc=Một mạng nhện dày bao phủ mọi thứ nơi đây. ###buffs actors.buffs.adrenaline.name=adrenaline -actors.buffs.adrenaline.desc=Một sự dâng trào sức mạnh vật lí, adrenaline giúp tăng cả tốc đ tấn công và di chuyển.\n\nAdrenaline khiến mục tiêu chạy với tốc độ gấp 2 lần và tấn công với tốc độ gấp 1.5 lần.\n\nSố lượt còn lại: %s. +actors.buffs.adrenaline.desc=Một sự dâng trào sức mạnh vật lí, adrenaline tăng cường cả tốc độ tấn công và di chuyển.\n\nAdrenaline khiến mục tiêu chạy với tốc độ gấp 2 lần và tấn công với tốc độ gấp 1.5 lần.\n\nLượt còn lại: %s. actors.buffs.adrenalinesurge.name=cường hóa sức mạnh -actors.buffs.adrenalinesurge.desc=Một sự dâng trào sức mạnh to lớn, nhưng đáng tiếc là không vĩnh viễn. \n\nCường hóa sức mạnh: +%d.\nSố lượt còn lại cho đến khi cường hóa yếu đi: %s. +actors.buffs.adrenalinesurge.desc=Một sự dâng trào sức mạnh to lớn, nhưng đáng tiếc là không vĩnh viễn. \n\nCường hóa sức mạnh: +%d.\nLượt còn lại cho đến khi cường hóa yếu đi: %s. actors.buffs.amok.name=điên cuồng -actors.buffs.amok.desc=Điên cuồng sẽ khiến mục tiêu vừa trở nên cực kì giận dữ vừa lú lẫn \n\nKhi một sinh vật trở nên điên cuồng, nó sẽ tấn công mọi thứ gần nó, không phân biệt bạn hay thù. \n\nSố lượt điên cuồng còn lại: %s. +actors.buffs.amok.desc=Điên cuồng sẽ khiến mục tiêu trở nên vừa cực kì giận dữ vừa lú lẫn \n\nKhi một sinh vật trở nên điên cuồng, nó sẽ tấn công mọi thứ gần nó, không phân biệt bạn hay thù. \n\nLượt điên cuồng còn lại: %s. actors.buffs.arcanearmor.name=áo giáp ma thuật actors.buffs.arcanearmor.desc=Một lớp khiên mỏng bao quanh bạn, kháng một phần sát thương từ các đòn tấn công phép. \n\nGiáp phép của bạn hiện được tăng cường từ: 0-%d. \nLượt còn lại đến khi giáp phép bị yếu đi: %s. actors.buffs.artifactrecharge.name=hồi năng cổ vật -actors.buffs.artifactrecharge.desc=Dòng năng lượng đang rạo rực trong bạn, các cổ vật mà bạn đang trang bị giờ đây sẽ được tăng tỉ lệ hồi phục lại năng lượng\n\nTuy mỗi cổ vật có tỉ lệ hồi khác nhau một chút, song năng lượng của chúng đều sẽ hồi phục lại nhanh hơn bình thường đáng kể.\n\nSố lượt còn lại: %s. +actors.buffs.artifactrecharge.desc=Năng lượng đang chảy trong bạn, tăng tốc độ hồi năng lượng của các cổ vật được bạn trang bị. \n\nTuy mỗi cổ vật sẽ bị ảnh hưởng khác nhau một chút, chúng sẽ đề hồi năng lượng nhanh hơn nhiều so với bình thường.\n\nLượt còn lại: %s. actors.buffs.ascensionchallenge.name=lời nguyền của tấm bùa actors.buffs.ascensionchallenge.desc=Bằng cách nào đó mà tên Yog-Dzewa vẫn có thể duy trì quyền lực của mình với thế giới này thông qua lá bùa, và hắn ta đang cố gắng ngăn bạn đi tiếp!\n\nNhờ sức mạnh của hắn mà giờ đây hầm ngục trở nên nguy hiểm hơn bao giờ hết, tăng số lượng của kẻ địch và khiến chúng trở nên mạnh mẽ hơn! Thứ sức mạnh này sẽ càng trở nên mạnh hơn nếu bạn lơ là, tuy nhiên, bạn có thể làm suy yếu nó bằng cách đánh bại những kẻ địch chịu ảnh hưởng từ sức mạnh của hắn. @@ -125,11 +125,11 @@ actors.buffs.bleeding.rankings_desc=Chảy máu đến chết actors.buffs.bleeding.desc=Vết thương đó đang chảy ra một lượng máu đáng lo ngại\n\nChảy máu gây sát thương theo lượt. Sát thương do chảy máu sẽ giảm một lượng ngẫu nhiên mỗi lượt, và chỉ dừng khi vết thương đóng lại.\n\nSát thương do chảy máu hiện tại: %d. actors.buffs.bless.name=được ban phước -actors.buffs.bless.desc=Một sự tập trung tuyệt vời, nghe nói rằng đó là sự ban phước của các vị thần.\n\nBan phước sẽ tăng độ chuẩn xác và khả năng né tránh thêm 25%%, khiến kẻ được nhận ban phước có thể chiến đấu hiệu quả hơn.\n\nSố lượt được ban phước còn lại: %s. +actors.buffs.bless.desc=Một nguồn tập trung to lớn, một số người nói rằng đó là sự ban phước của các vị thần.\n\nBan phước sẽ tăng độ chuẩn xác và khả năng né tránh thêm 25%%, khiến người được ban phước chiến đấu hiệu quả hơn nhiều.\n\nLượt ban phước còn lại: %s. actors.buffs.blindness.name=mù actors.buffs.blindness.heromsg=Bạn đã bị mù! -actors.buffs.blindness.desc=Sự mù loà biến thế giới xung quanh thành một màn sương tăm tối.\n\nKhi bị mù, tầm nhìn của một nhân vật bị giảm còn một ô, khiến các đòn tấn công từ xa trở nên vô dụng và rất dễ mất dấu các kẻ thù ở xa. Ngoài ra, một người hùng bị mù không thể đọc các cuộn giấy hay sách.\n\nSố lượt bị mù còn lại: %s. +actors.buffs.blindness.desc=Sự mù loà biến thế giới xung quanh thành một màn sương tăm tối.\n\nKhi bị mù, tầm nhìn của một nhân vật bị giảm còn một ô, khiến các đòn tấn công từ xa trở nên vô dụng và rất dễ mất dấu các kẻ thù ở xa. Ngoài ra, một người hùng bị mù không thể đọc các cuộn giấy hay sách.\n\nLượt bị mù còn lại: %s. actors.buffs.buff.heromsg= @@ -138,7 +138,7 @@ actors.buffs.burning.heromsg=Bạn đang bị cháy! actors.buffs.burning.burnsup=%s đã bốc cháy! actors.buffs.burning.ondeath=Bạn đã bị cháy cho đến chết... actors.buffs.burning.rankings_desc=Cháy thành tro -actors.buffs.burning.desc=Trên đời này chỉ có một vài thứ là khó chịu hơn cảm giác bị nhấn chìm trong lửa.\n\nLửa sẽ gây sát thương mỗi lượt cho đến khi nó bị dập tắt hoặc tự tắt. Bạn có thể dập lửa bằng cách bước vào nước, hoặc đập một lọ thuốc.\n\nThêm nữa, các vật phẩm và địa hình dễ bắt lửa sẽ bị cháy khi tiếp xúc với lửa.\n\nSố lượt bị cháy còn lại: %s. +actors.buffs.burning.desc=Trên đời này không có nhiều thứ khó chịu hơn là bị nhấn chìm trong lửa.\n\nLửa sẽ gây sát thương mỗi lượt cho đến khi nó bị dập tắt hoặc tự tắt. Lửa có thể được dập bằng cách bước vào nước, hoặc từ nước bắn ra từ một lọ thuốc vỡ.\n\nThêm nữa, địa hình hoặc vật phẩm dễ cháy có thể bị đốt cháy khi tiếp xúc với lửa.\n\nLượt cháy còn lại: %s. actors.buffs.championenemy.warn=Bạn cảm thấy một sự hiện diện đầy sát khí. actors.buffs.championenemy$blazing.name=nhà vô địch rực lửa @@ -157,11 +157,11 @@ actors.buffs.championenemy$growing.desc=Nhà vô địch phát triển được actors.buffs.charm.name=mê hoặc actors.buffs.charm.heromsg=Bạn đã bị mê hoặc! actors.buffs.charm.cant_attack=Bạn đã bị mê hoặc bởi kẻ địch đó và không thể tấn công chúng. -actors.buffs.charm.desc=Mê hoặc là phép thuật thao túng có thể khiến kẻ thù tạm thời quý mến nhau.\n\nNhân vật bị ảnh hưởng bởi mê hoặc không thể tấn công trực tiếp kẻ thù đã mê hoặc mình. Tuy nhiên, việc tấn công các mục tiêu khác vẫn là có thể. Đau đớn sẽ làm giảm thời gian của mê hoặc. \n\nSố lượt bị mê hoặc còn lại: %s. +actors.buffs.charm.desc=Mê hoặc là phép thuật thao túng có thể khiến kẻ thù tạm thời quý mến nhau.\n\nNhân vật bị ảnh hưởng bởi mê hoặc không thể tấn công trực tiếp kẻ thù đã mê hoặc mình. Tuy nhiên, việc tấn công các mục tiêu khác vẫn là có thể. Cú sốc của cơn đau sẽ làm giảm thời lượng của mê hoặc. \n\nLượt mê hoặc còn lại: %s. actors.buffs.chill.name=lạnh cóng actors.buffs.chill.freezes=%s bị đóng băng! -actors.buffs.chill.desc=Không đến mức đóng băng, nhưng vẫn quá lạnh.\n\nTất cả hành động của mục tiêu bị Lạnh cóng sẽ trở nên chậm chạp hơn, phụ thuộc vào số lượt còn lại của hiệu ứng. Trường hợp tệ nhất, nó tương đương với bị làm chậm.\n\nSố lượt lạnh cóng còn lại: %1$s.\nTốc độ bị giảm đi: %2$s%%. +actors.buffs.chill.desc=Không đến mức đóng băng, nhưng vẫn quá lạnh.\n\nMục tiêu bị lạnh cóng thực hiện mọi hành động chậm chạp hơn, phụ thuộc vào số lượt còn lại của hiệu ứng. Ở mức tệ nhất, nó tương đương với bị làm chậm.\n\nLượt lạnh cóng còn lại: %1$s.\nTốc độ bị giảm đi: %2$s%%. actors.buffs.combo.name=combo actors.buffs.combo.action_name=đòn tấn công liên hoàn @@ -190,7 +190,7 @@ actors.buffs.corruption.desc=Sự tha hóa thâm nhập vào linh hồn của si actors.buffs.cripple.name=què actors.buffs.cripple.heromsg=Bạn đã bị què! -actors.buffs.cripple.desc=Bạn khá chắc rằng chân mình không được sinh ra để bị bẻ cong như thế.\n\nQuè quặt sẽ giảm một nửa tốc độ di chuyển, khiến việc đi một ô thường mất hai lượt thay vì một.\n\nSố lượt bị què còn lại: %s. +actors.buffs.cripple.desc=Bạn khá chắc rằng chân mình không được sinh ra để bị bẻ cong như thế.\n\nBị què sẽ giảm một nửa tốc độ di chuyển, khiến việc đi một ô thường mất hai lượt thay vì một.\n\nLượt què còn lại: %s. actors.buffs.daze.name=choáng váng actors.buffs.daze.heromsg=Bạn bị choáng váng! @@ -223,7 +223,7 @@ actors.buffs.foresight.desc=Bằng cách nào đó mà bạn có thể thấy đ actors.buffs.frost.name=đóng băng actors.buffs.frost.freezes=%s bị đóng băng! -actors.buffs.frost.desc=Không nên nhầm lẫn với trạng thái đông đặc, trạng thái đóng băng này chỉ bao bọc mục tiêu lại bằng một lớp băng dày.\n\nĐóng băng hoạt động tương tự như Tê liệt, mục tiêu sẽ không thể cử động được. Không như Tê liệt, kẻ địch sẽ ngay lập tức được rã băng nếu chúng nhận sát thương, vì lớp băng sẽ bị vỡ ra.\n\nSố lượt đóng băng còn lại: %s. +actors.buffs.frost.desc=Không nên nhầm lẫn với hoá thành băng, trạng thái đóng băng nhẹ nhàng hơn này chỉ bao bọc mục tiêu lại trong băng.\n\nĐóng băng hoạt động tương tự như tê liệt, mục tiêu sẽ không thể hành động được. Không như tê liệt, kẻ địch sẽ ngay lập tức được rã băng nếu chúng nhận sát thương, vì lớp băng sẽ vỡ ra.\n\nLượt đóng băng còn lại: %s. actors.buffs.frostimbue.name=hòa nhập với băng actors.buffs.frostimbue.desc=Bạn đã được hoà nhập với sức mạnh của băng!\n\nMọi đòn tấn công vật lí sẽ từ từ cộng dồn hiệu ứng lạnh lên kẻ địch. Thêm vào đó, bạn sẽ miễn nhiễm hoàn toàn với cái lạnh\n\nLượt hoà nhập với băng còn lại: %s. @@ -241,16 +241,16 @@ actors.buffs.gravitychaostracker.desc_positive=Nhưng có vẻ bạn và các đ actors.buffs.gravitychaostracker.desc_duration=Không rõ hiệu ứng này sẽ kéo dài bao lâu, nhưng nó không thể kéo dài mãi mãi được. actors.buffs.greaterhaste.name=siêu nhanh nhẹn -actors.buffs.greaterhaste.desc=Một sự tăng cường tốc độ khổng lồ, cứ như thể tất cả những thứ khác đang đứng yên trong một thời gian ngắn.\n\nKhi đang mang hiệu ứng siêu nhanh nhẹn, các hành động di chuyển không hề tốn thời gian, nhưng các hành động khác vẫn được thực hiện ở tốc độ thông thường. Mỗi bước di chuyển sẽ tiêu tốn một lượt siêu nhanh nhẹn.\n\nSố lượt siêu nhanh nhẹn còn lại: %d. +actors.buffs.greaterhaste.desc=Một sự tăng cường tốc độ khổng lồ, cứ như thể tất cả những thứ khác đang đứng yên trong một thời gian ngắn.\n\nKhi đang mang hiệu ứng siêu nhanh nhẹn, các hành động di chuyển không hề tốn thời gian, nhưng các hành động khác vẫn được thực hiện ở tốc độ thông thường. Mỗi bước di chuyển sẽ tiêu tốn một lượt siêu nhanh nhẹn.\n\nLượt siêu nhanh nhẹn còn lại: %d. actors.buffs.haste.name=nhanh nhẹn actors.buffs.haste.desc=Năng lượng chảy cuồn cuộn trong cơ bắp, làm bạn chạy với vận tốc phi thường!\n\nKhi chịu tác dụng của nhanh nhẹn bạn sẽ chạy với 3x tốc độ, nhưng mọi hành động khác vẫn ở tốc độ thường.\n\nLượt nhanh nhẹn còn lại: %s. actors.buffs.healing.name=hồi phục -actors.buffs.healing.desc=Một liều hồi phục thần kì làm cho liền da lành thịt.\n\nMỗi lượt máu sẽ hồi đều đặn cho đến khi hồi máu kết thúc. Lượng máu hồi có thể phai dần theo thời gian.\n\nHồi máu tiếp: %d.\n\nHồi máu còn lại: %d. +actors.buffs.healing.desc=Một phương thuốc thần kì đang khiến các vết thương đóng và da thịt liền lại.\n\nMỗi lượt, sinh lực sẽ hồi từ từ cho đến khi hiệu ứng hồi phục kết thúc. Lượng hồi phục có thể giảm dần theo thời gian.\n\nHồi phục kế tiếp: %d.\n\nHồi phục còn lại: %d. actors.buffs.herodisguise.name=cải trang -actors.buffs.herodisguise.desc=Phép thuật ảo ảnh đã thay đổi ngoại hình của bạn! Hiệu ứng này không có tác dụng nào khác, nhưng dù vậy vẫn có cảm giác rất lạ.\n\nSố lượt cải trang còn lại: %s. +actors.buffs.herodisguise.desc=Phép thuật ảo ảnh đã thay đổi ngoại hình của bạn! Hiệu ứng này hoàn toàn chỉ là về hình ảnh, nhưng dù vậy vẫn có cảm giác rất lạ.\n\nLượt cải trang còn lại: %s. actors.buffs.hex.name=trúng phép actors.buffs.hex.heromsg=Bạn đã bị trúng phép! @@ -271,13 +271,13 @@ actors.buffs.hunger.desc_intro_starving=Bạn đói đến mức bắt đầu c actors.buffs.hunger.desc=\n\nCơn đói sẽ càng lúc càng tăng lên khi bạn ở lâu trong hầm ngục, và cuối cùng bạn sẽ bắt đầu chết đói. Khi đó, bạn sẽ dần mất sinh lực thay vì hồi phục nó.\n\nChia khẩu phần ăn là rất quan trọng! Nếu bạn còn nhiều sinh lực, chịu đói một chút sẽ không phải là ý tồi nếu như sẽ có thêm thức ăn sau. Ăn theo khẩu phần hiệu quả có thể giúp tiết kiệm thức ăn lâu hơn! actors.buffs.invisibility.name=tàng hình -actors.buffs.invisibility.desc=Bạn hoàn toàn ẩn mình vào địa hình xung quanh, khiến bạn không thể bị nhìn thấy.\n\nKhi bạn đang tàng hình kẻ địch không thể tấn công hoặc đuổi theo bạn. Các đòn tấn công vật lí và hiệu ứng phép thuật (như các cuộn giấy và đũa phép) sẽ ngay lập tức hủy Tàng hình.\n\nSố lượt tàng hình còn lại: %s. +actors.buffs.invisibility.desc=Bạn hoàn toàn ẩn mình vào địa hình xung quanh, khiến bạn không thể bị nhìn thấy.\n\nKhi bạn đang tàng hình kẻ địch không thể tấn công hoặc đuổi theo bạn. Các đòn tấn công vật lí và hiệu ứng phép thuật (như các cuộn giấy và đũa phép) sẽ ngay lập tức hủy tàng hình.\n\nLượt tàng hình còn lại: %s. actors.buffs.invulnerability.name=miễn nhiễm sát thương -actors.buffs.invulnerability.desc=Nhân vật này đang được bao bọc bởi một sức mạnh bảo vệ mạnh mẽ, trao cho họ một khoảng thời gian miễn nhiễm sát thương ngắn!\n\nSố lượt còn lại: %s. +actors.buffs.invulnerability.desc=Nhân vật này đang được bao bọc bởi một sức mạnh bảo vệ mạnh mẽ, trao cho họ một khoảng thời gian miễn nhiễm sát thương ngắn!\n\nLượt còn lại: %s. actors.buffs.levitation.name=lơ lửng -actors.buffs.levitation.desc=Một lực phép thuật đang nhấc bổng bạn lên khỏi mặt đất, khiến bạn cảm thấy nhẹ bẫng.\n\nCác nhân vật đang bay sẽ di chuyện lặng lẽ và không chịu mọi hiệu ứng từ mặt đất. Bẫy sẽ không bị kích hoạt, nước sẽ không dập được lửa, cây cỏ sẽ không bị dẫm lên, rễ cây sẽ không với tới bạn, và bạn sẽ bay qua các hố sâu. Nhưng hãy cẩn thận, bởi tất cả những thứ đó sẽ có hiệu lực trở lại ngay khi hiệu ứng bay kết thúc!\n\nSố lượt bay còn lại: %s. +actors.buffs.levitation.desc=Một lực phép thuật đang nhấc bổng bạn lên khỏi mặt đất, khiến bạn cảm thấy nhẹ bẫng.\n\nCác nhân vật đang bay sẽ di chuyện lặng lẽ và không chịu mọi hiệu ứng từ mặt đất. Bẫy sẽ không bị kích hoạt, nước sẽ không dập được lửa, cây cỏ sẽ không bị dẫm lên, rễ sẽ không bám vào bạn, và bạn sẽ bay qua các hố sâu. Nhưng hãy cẩn thận, bởi tất cả những thứ đó sẽ có hiệu lực trở lại ngay khi hiệu ứng bay kết thúc!\n\nLượt bay còn lại: %s. actors.buffs.lifelink.name=liên kết sự sống actors.buffs.lifelink.ondeath=Sát thương liên kết sự sống đã giết bạn... @@ -305,7 +305,7 @@ actors.buffs.magicimmune.name=miễn nhiễm phép thuật actors.buffs.magicimmune.desc=Mọi hiệu ứng phép thuật giờ không thể tác động lên bạn, bạn hoàn toàn không thể bị ảnh hưởng bởi chúng.\n\nKhi miễn nhiễm phép thuật, tất cả hiệu ứng phép thuật có lợi và có hại sẽ không tác động đến bạn, bao gồm các lời nguyền, phù phép, đũa phép, cuộn giấy, nhẫn, cổ vật,... Các kĩ năng của áo giáp người hùng đủ mạnh để hoạt động bất kể hiệu ứng này. \n\nLượt miễn nhiễm phép thuật còn lại: %s. actors.buffs.mindvision.name=tâm nhãn -actors.buffs.mindvision.desc=Bằng cách nào đó bạn có thể nhìn thấy mọi sinh vật trên tầng này qua tâm trí của bạn. Nó là một cảm giác kì lạ.\n\nBạn sẽ còn nhìn thấy được mọi nhân vật trong tầng này miễn là bạn còn tâm nhãn. Việc nhìn thấy sinh vật qua tâm nhãn cũng được xem như là nó đang bị theo dõi hoặc được đứng gần nó để phục vụ cho mục đích của nhiều hiệu ứng phép thuật.\n\nSố lượt tâm nhãn còn lại: %s. +actors.buffs.mindvision.desc=Bằng cách nào đó bạn có thể nhìn thấy mọi sinh vật trên tầng này qua tâm trí của bạn. Nó là một cảm giác kì lạ.\n\nBạn sẽ còn nhìn thấy được mọi nhân vật trong tầng này miễn là bạn còn tâm nhãn. Việc nhìn thấy sinh vật qua tâm nhãn cũng được xem như là nó đang bị theo dõi hoặc được đứng gần nó để phục vụ cho mục đích của nhiều hiệu ứng phép thuật.\n\nLượt tâm nhãn còn lại: %s. actors.buffs.momentum.momentum=tích lũy động năng actors.buffs.momentum.running=đang chạy @@ -342,7 +342,7 @@ actors.buffs.ooze.name=chất nhầy ăn da actors.buffs.ooze.heromsg=Chất nhầy ăn mòn da thịt của bạn. Hãy rửa trôi nó đi! actors.buffs.ooze.ondeath=Bạn đã bị tan chảy... actors.buffs.ooze.rankings_desc=Đã bị hoà tan -actors.buffs.ooze.desc=Thứ axit dính này bám vào da thịt, ăn mòn và làm tan chảy nó một cách chậm rãi.\n\nChất nhầy sẽ gây sát thương cố định theo thời gian, nhưng có thể được rửa sạch ngay lập tức trong nước.\n\nSố lượt bị dính axit còn lại: %s. +actors.buffs.ooze.desc=Thứ axit dính này bám vào da thịt, ăn mòn và làm tan chảy nó một cách chậm rãi.\n\nChất nhầy sẽ gây sát thương cố định theo thời gian, nhưng có thể được rửa sạch ngay lập tức trong nước.\n\nLượt chất nhầy còn lại: %s. actors.buffs.paralysis.name=tê liệt actors.buffs.paralysis.heromsg=Bạn bị tê liệt! @@ -1445,7 +1445,7 @@ actors.mobs.npcs.wandmaker.desc=Quý ông già nhưng mạnh khỏe này mang m ###mobs actors.mobs.acidic.name=bọ cạp có tính axit -actors.mobs.acidic.desc=Sinh vật quỷ quái giống nhện này cố tránh cận chiến, ưa bắn ra các răng cưa gai từ tầm xa. Có những giọt nước độc đang rỉ ra từ nó. +actors.mobs.acidic.desc=Những sinh vật ác quỷ giống nhện này tránh chiến đấu tầm gần, chúng thích bắn các gai có răng cưa gây què từ khoảng cách xa hơn. Con này có vẻ đang chảy ra chất nhầy ăn mòn. actors.mobs.albino.name=chuột bạch tạng actors.mobs.albino.desc=Đây là một giống chuột có túi hiếm, với bộ lông trắng tinh và hàm răng lởm chởm. @@ -1577,7 +1577,7 @@ actors.mobs.eye.deathgaze_kill=Ánh nhìn chết đã giết bạn actors.mobs.eye.desc=Mắt quỷ là những quả cầu năng lượng quỷ được nén bay lơ lửng. Mặc dù chúng có khả năng cận chiến nhưng sức mạnh thực sự của chúng đến từ phép thuật của chúng.\n\nSau khi tích năng lượng trong một thời gian ngắn, Mắt quỷ sẽ giải phóng một chùm năng lượng hủy diệt được gọi là _ánh nhìn chết._ Bất cứ thứ gì trong tầm ngắm của Mắt quỷ sẽ chịu sát thương to lớn, những nhà thám hiểm khôn ngoan sẽ chạy tìm chỗ trốn. actors.mobs.fetidrat.name=chuột thối -actors.mobs.fetidrat.desc=Có điều gì đó sai sai với con chuột này. Bộ lông bóng nhờn màu đen, da thối rữa khác hẳn lũ chuột bình thường bạn từng thấy. Đôi mắt tái nhợt càng làm nó đáng sợ.\n\nNó mang theo một làn khí thối quanh người, cực kì nguy hiểm ở gần.\n\nChất nhờn độc đang chảy ra từ miệng nó, ăn mòn cả nền sàn nhưng có vẻ bị phân giải trong nước. +actors.mobs.fetidrat.desc=Rõ ràng có điều gì đó không ổn với con chuột này. Bộ lông đen dính mỡ và lớp da thối rữa của nó khác hẳn những con chuột khoẻ mạnh bạn đã thấy trước đây. Đôi mắt xanh nhạt của nó khiến nó trông đặc biệt nguy hiểm.\n\nNó mang một làn khí hôi thối kinh khủng theo mình, mạnh đến áp đảo ở gần.\n\nChất nhầy đen chảy ra từ miệng của con chuột, ăn mòn sàn ngục nhưng có vẻ tan ra trong nước. actors.mobs.fetidrat.discover_hint=Bạn có thể tìm thấy kẻ địch này trong một nhiệm vụ nhất định. actors.mobs.fungalcore.name=lõi nấm @@ -1711,7 +1711,7 @@ actors.mobs.rotlasher.desc=Dây roi thối là một phần trong cấu trúc r actors.mobs.rotlasher.discover_hint=Bạn có thể tìm thấy kẻ địch này trong một nhiệm vụ nhất định. actors.mobs.scorpio.name=bọ cạp -actors.mobs.scorpio.desc=Những sinh vật quỷ khổng lồ giống loài nhện này tránh cận chiến, chúng thích bắn những chiếc gai có răng cưa gây què từ khoảng cách xa. +actors.mobs.scorpio.desc=Những sinh vật ác quỷ giống nhện này tránh chiến đấu tầm gần, chúng thích bắn các gai có răng cưa gây què từ khoảng cách xa hơn. actors.mobs.senior.name=tu sĩ già actors.mobs.senior.desc=Những tu sĩ này là những kẻ cuồng tín, những người đã cống hiến hết mình để bảo vệ nhà vua của họ bằng sức mạnh thể lực của họ. Sự tận tâm của họ lớn đến mức họ đã hoàn toàn giao nộp tâm trí của họ cho vị vua của họ, và giờ đây lang thang trong thành phố lùn như những thây ma vô hồn\n\nTu sĩ này đã thành thạo kỹ thuật cận chiến, và có khả năng tích lũy sự tập trung khi di chuyển nhanh hơn nhiều so với những tu sĩ thông thường. Khi chúng trở nên tập trung, tu sĩ sẽ phản lại đòn tấn công vật lí kế tiếp được nhắm vào chúng, ngay cả khi nó đáng lẽ sẽ chắc chắn trúng. Các tu sĩ tích lũy sự tập trung nhanh hơn khi đang di chuyển và chậm hơn khi chiến đấu trực tiếp. diff --git a/core/src/main/assets/messages/actors/actors_zh-hant.properties b/core/src/main/assets/messages/actors/actors_zh-hant.properties index 5c1752372..d81d8c3eb 100644 --- a/core/src/main/assets/messages/actors/actors_zh-hant.properties +++ b/core/src/main/assets/messages/actors/actors_zh-hant.properties @@ -1350,11 +1350,11 @@ actors.mobs.npcs.ghost.find_me=謝謝你……來找我吧…… actors.mobs.npcs.ghost.desc=這個幽靈幾乎不能被看見。它看起來像是由一片無形的昏暗光斑和一張悲痛的面孔所組成的。 actors.mobs.npcs.imp.name=野心勃勃的小惡魔 -actors.mobs.npcs.imp.intro=你是一名冒險家嗎? 我最愛冒險家了! 在需要殺掉什麼的時候他們總是最可靠了,我說的沒錯吧? 報酬?當然有啦 ;) +actors.mobs.npcs.imp.intro=你是一名冒險家嗎? 我最愛冒險家了! 在需要殺掉什麼的時候他們總是最可靠了,我說的沒錯吧? 報酬?當然有啦 ; ) actors.mobs.npcs.imp.golems_1=總之,我需要你殺一些_魔像_。 你看,我要在這裡開始搞點小本生意,但這些愚蠢的傀儡只會毀掉我的生意! 跟這些發著光的大個子花崗岩根本沒法交流,真是該死! 所以殺死……我想想,_4個魔像_,然後獎勵就是你的了。 actors.mobs.npcs.imp.monks_1=總之,我需要你殺一些_武僧_。 你看,我要在這裡開始搞點小本生意,但這些瘋子不買任何東西還會嚇跑顧客。 所以殺死……我想想,_5位武僧_,然後獎勵就是你的了。 -actors.mobs.npcs.imp.golems_2=喔,你還活著!我就知道你的頭比它們更硬;) 只要別忘了撿走它們的徽記就好。 -actors.mobs.npcs.imp.monks_2=喔,你還活著!我就知道你的功夫比他們更強;) 只要別忘了撿走他們的徽記就好。 +actors.mobs.npcs.imp.golems_2=喔,你還活著!我就知道你的頭比它們更硬; ) 只要別忘了撿走它們的徽記就好。 +actors.mobs.npcs.imp.monks_2=喔,你還活著!我就知道你的功夫比他們更強; ) 只要別忘了撿走他們的徽記就好。 actors.mobs.npcs.imp.cya=我們會再見面的,%s! actors.mobs.npcs.imp.hey=喂喂喂,%s! actors.mobs.npcs.imp.desc=小惡魔是一種低等惡魔。它們既沒有強大的力量也沒有魔法天賦,但他們相當聰明而且善於交際。許多小惡魔都喜歡生活在沒有其他惡魔存在的地方。 @@ -1398,7 +1398,7 @@ actors.mobs.npcs.sheep.name=綿羊 actors.mobs.npcs.sheep.baa!=咩! actors.mobs.npcs.sheep.baa?=咩? actors.mobs.npcs.sheep.baa.=咩。 -actors.mobs.npcs.sheep.baa...=咩…… +actors.mobs.npcs.sheep.baa...=咩… actors.mobs.npcs.sheep.def_verb=格擋 actors.mobs.npcs.sheep.desc=這是一隻魔法綿羊。為什麼叫牠魔法綿羊?因為你殺不死牠。牠只會站在那裡直到牠消失,牠會做的事情只有邊反芻邊對你翻白眼。 actors.mobs.npcs.sheep.discover_hint=此角色可被某種物品與陷阱召喚。 @@ -1419,7 +1419,7 @@ actors.mobs.npcs.shopkeeper.talk_prison_duelist=哦,這不是正在旅行的 actors.mobs.npcs.shopkeeper.talk_prison_cleric=唉呦,是殿下啊,現在又升遷成聖下啦?嘻嘻,這裡有個更好的問題:你工作不好好做來這做啥?你應該知道你的死對那些信徒可是重大打擊吧。不如這樣吧:我相信你在上層絕對有撿到錢,你把那些對你沒用的穢物給我,我給你些能讓你活著出去的東西,意下如何? actors.mobs.npcs.shopkeeper.talk_caves=花錢,是為了走更長遠的路。\n\n喔,還有,如果你在底下見到我那巨魔老友,替我向他問好。順便催那塊石頭把上禮拜槌子的錢給我結清! actors.mobs.npcs.shopkeeper.talk_city=我的商品可以保證你在這裡的安全。\n\n但拜託不要在這裡閒晃。我不知道花了多久才讓這邊的"居民"不靠近我,我可不想要你帶來更多麻煩! -actors.mobs.npcs.shopkeeper.talk_halls=哈嘍!我為了獵魔人準備了特別的優惠!\n\n對了,下去時可要小心點!底下的惡魔可不管你有多勇敢。如果你死了就沒辦法回來花更多錢啦! ;)\n那些惡魔和我像嗎? 嘿嘿,當然不是。我只是一個小家伙,不會打架,還保住了我的意識。底下的惡魔都非常強,還被奴化了,是被……呃,總之下去時小心點。 +actors.mobs.npcs.shopkeeper.talk_halls=哈嘍!我為了獵魔人準備了特別的優惠!\n\n對了,下去時可要小心點!底下的惡魔可不管你有多勇敢。如果你死了就沒辦法回來花更多錢啦! ; )\n那些惡魔和我像嗎? 嘿嘿,當然不是。我只是一個小家伙,不會打架,還保住了我的意識。底下的惡魔都非常強,還被奴化了,是被……呃,總之下去時小心點。 actors.mobs.npcs.shopkeeper.talk_ascent=無論你想要拿護符做什麼,我可不想與你有所瓜葛。要買東西就快點,我們都該走人了! actors.mobs.npcs.shopkeeper.desc=這位矮胖的傢伙看起來更適合在某些大城市裡做買賣而不是這種地下城。這些商品的價格解釋了為什麼他會喜歡在這地方做生意。 diff --git a/core/src/main/assets/messages/items/items_vi.properties b/core/src/main/assets/messages/items/items_vi.properties index 341291e2c..232806c0e 100644 --- a/core/src/main/assets/messages/items/items_vi.properties +++ b/core/src/main/assets/messages/items/items_vi.properties @@ -2112,7 +2112,7 @@ items.weapon.missiles.darts.dart.desc=Những trục gỗ nhọn đơn giản n items.weapon.missiles.darts.dart.unlimited_uses=Nhờ cấu tạo đơn giản của chúng, phi tiêu có thể coi là sẽ dùng được vĩnh viễn. items.weapon.missiles.darts.displacingdart.name=phi tiêu dịch chuyển -items.weapon.missiles.darts.displacingdart.desc=Những chiếc phi tiêu này được tẩm bằng một hợp chất dựa trên lá dịch chuyển và sẽ dịch chuyển mục tiêu của chúng đi một khoảng cách ngắn. +items.weapon.missiles.darts.displacingdart.desc=Những chiếc phi tiêu này được tẩm bằng một hợp chất dựa trên lá biến mất và sẽ dịch chuyển mục tiêu của chúng đi một khoảng cách ngắn. items.weapon.missiles.darts.healingdart.name=phi tiêu hồi phục items.weapon.missiles.darts.healingdart.desc=Những chiếc phi tiêu này được tẩm một hợp chất dựa trên cỏ mặt trời giúp hồi phục mục tiêu của chúng. Bản thân phi tiêu vẫn có hại với kẻ địch, nhưng sẽ không làm hại đồng minh. diff --git a/core/src/main/assets/messages/items/items_zh-hant.properties b/core/src/main/assets/messages/items/items_zh-hant.properties index 13923f569..638591a4c 100644 --- a/core/src/main/assets/messages/items/items_zh-hant.properties +++ b/core/src/main/assets/messages/items/items_zh-hant.properties @@ -916,7 +916,7 @@ items.quest.dwarftoken.desc=很多矮人和他們的造物都攜帶著這種小 items.quest.dwarftoken.discover_hint=此物品會在某任務中出現。 items.quest.embers.name=元素餘燼 -items.quest.embers.desc=只能從新生火元素身上採集到的特殊餘燼.。它們散發著溫暖的能量。 +items.quest.embers.desc=只能從新生火元素身上採集到的特殊餘燼。它們散發著溫暖的能量。 items.quest.embers.discover_hint=此物品會在某任務中出現。 items.quest.gooblob.name=蝕黑黏液 @@ -1234,7 +1234,7 @@ items.scrolls.exotic.scrollofpassage.name=歸返秘卷 items.scrolls.exotic.scrollofpassage.desc=卷軸上的法術會閱讀者回到所在區域的第一層入口。很適合用以快速抵達商店。 items.scrolls.exotic.scrollofprismaticimage.name=幻衛秘卷 -items.scrolls.exotic.scrollofprismaticimage.desc=這種秘卷上的咒文會創造閱讀者的一個幻影。 這個像使用者的弱化版克隆體的幻影有著相同的防禦,但生命值和造成的傷害更低。\n\n幻影將吸引敵人的火力從而保護閱讀者。\n\n當幻影存在時閱讀這張秘卷將會為其恢復所有生命。 +items.scrolls.exotic.scrollofprismaticimage.desc=這種秘卷上的咒文會創造閱讀者的一個幻影。 這個像使用者的弱化版複製體的幻影有著相同的防禦,但生命值和造成的傷害更低。\n\n幻影將吸引敵人的火力從而保護閱讀者。\n\n當幻影存在時閱讀這張秘卷將會為其恢復所有生命。 items.scrolls.exotic.scrollofpsionicblast.name=靈能震爆秘卷 items.scrolls.exotic.scrollofpsionicblast.ondeath=靈能震爆撕碎了你的意識…… diff --git a/core/src/main/assets/messages/levels/levels_vi.properties b/core/src/main/assets/messages/levels/levels_vi.properties index 8eda0a131..a55ce92da 100644 --- a/core/src/main/assets/messages/levels/levels_vi.properties +++ b/core/src/main/assets/messages/levels/levels_vi.properties @@ -56,7 +56,7 @@ levels.traps.cursingtrap.desc=Cái bẫy này chứa cùng thứ phép thuật h levels.traps.disarmingtrap.name=bẫy tước vũ khí levels.traps.disarmingtrap.disarm=Vũ khí của bạn bị dịch chuyển đi! -levels.traps.disarmingtrap.desc=Cái bẫy này chứa phép thuật dịch chuyển tức thời rất cụ thể, nó sẽ đưa vũ khí của nạn nhân của nó đến một số vị trí khác. +levels.traps.disarmingtrap.desc=Cái bẫy này chứa phép thuật dịch chuyển rất cụ thể, nó sẽ dịch chuyển vũ khí của nạn nhân của nó đến một vị trí nào đó khác. levels.traps.disintegrationtrap.name=bẫy tan rã levels.traps.disintegrationtrap.one=Cái bẫy phân rã %s của bạn! @@ -144,7 +144,7 @@ levels.traps.corrosiontrap.name=bẫy khí ăn mòn levels.traps.corrosiontrap.desc=Kích hoạt cái bẫy này sẽ làm một đám mây khí có tính axit chết người thoát ra trong khu vực xung quanh. levels.traps.warpingtrap.name=bẫy di dời -levels.traps.warpingtrap.desc=Cái bẫy này tương tự như một cái bẫy dịch chuyển tức thời, nhưng cũng sẽ khiến người hùng mất đi hiểu biết của họ về bố cục của tầng! +levels.traps.warpingtrap.desc=Cái bẫy này giống như một cái bẫy dịch chuyển, nhưng cũng sẽ khiến người hùng mất đi hiểu biết của mình về bố cục của tầng! levels.traps.weakeningtrap.name=bẫy suy yếu levels.traps.weakeningtrap.desc=Phép thuật hắc ám trong cái bẫy này hút năng lượng ra khỏi bất cứ thứ gì tiếp xúc với nó. Tuy nhiên, những kẻ địch mạnh mẽ có thể sẽ kháng lại hiệu ứng. diff --git a/core/src/main/assets/messages/misc/misc_eo.properties b/core/src/main/assets/messages/misc/misc_eo.properties index e06880ee1..efb5ec3f8 100644 --- a/core/src/main/assets/messages/misc/misc_eo.properties +++ b/core/src/main/assets/messages/misc/misc_eo.properties @@ -205,7 +205,7 @@ badges$badge.unlock_cleric.desc=Malŝlosi Klerikon per plene forigi malbenon de badges$badge.enemy_hazards.title=Sekureca danĝeraĵo badges$badge.enemy_hazards.desc=Mortigi 10 malamikojn dum unu ludo kun helpo de ĉirkaŭaĵaj danĝeraĵoj (kaptiloj, kreskaĵoj kaj abismoj) badges$badge.many_buffs.title=Plurkolore -badges$badge.many_buffs.desc=Havi almenaŭ 10 bildsimbolojn de efikoj aktivaj samtempe +badges$badge.many_buffs.desc=Havi almenaŭ 10 bildsimbolojn de efikoj aktivajn samtempe badges$badge.pacifist_ascent.title=Pacifista supreniro badges$badge.pacifist_ascent.desc=Preni la Amuleton de Jendor’ al la supraĵo sen redukti ĝian malbenon badges$badge.taking_the_mick.title=Primoki la antikvan dion diff --git a/core/src/main/assets/messages/plants/plants_vi.properties b/core/src/main/assets/messages/plants/plants_vi.properties index 66df30230..d919f5c78 100644 --- a/core/src/main/assets/messages/plants/plants_vi.properties +++ b/core/src/main/assets/messages/plants/plants_vi.properties @@ -21,10 +21,10 @@ plants.earthroot$seed.name=Hạt cây rễ đất plants.earthroot$armor.name=áo giáp thảo mộc plants.earthroot$armor.desc=Một loại giáp tự nhiên, bất động làm từ vỏ cây và dây.\n\nBộ giáp thiên nhiên này sẽ chặn %d sát thương từ bất cứ đòn vật lí nào, cho đến khi nó hết độ bền và vỡ vụn.\n\nBởi bộ giáp bất động, di chuyển sẽ khiến nó vỡ ra và bị mất.\n\nGiáp còn lại: %d. -plants.fadeleaf.name=Lá dịch chuyển +plants.fadeleaf.name=lá biến mất plants.fadeleaf.desc=Chạm vào một cây lá biến mất sẽ dịch chuyển bất kì sinh vật nào tới một nơi ngẫu nhiên trên tầng hiện tại. -plants.fadeleaf.warden_desc=Hiệu ứng dịch chuyển của lá mạnh hơn đối với _Hộ vệ_, dịch chuyển cô trở lại điểm kết thúc của tầng hầm ngục trước. -plants.fadeleaf$seed.name=hạt cây lá dịch chuyển +plants.fadeleaf.warden_desc=Hiệu ứng dịch chuyển của lá biến mất mạnh hơn đối với _Hộ vệ_, dịch chuyển cô trở lại điểm kết thúc của tầng ngục trước. +plants.fadeleaf$seed.name=hạt cây lá biến mất plants.firebloom.name=hoa lửa plants.firebloom.desc=Khi bất cứ thứ gì chạm vào nó, nó sẽ bốc cháy với đám lửa dữ dội. diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java index 19e9fbd7d..e57e3c5fd 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/changelist/v3_X_Changes.java @@ -91,7 +91,7 @@ public class v3_X_Changes { changeInfos.add(changes); changes.addButton( new ChangeButton(Icons.get(Icons.SHPX), "Dev Commentary", - "...")); + "v3.2.5 has a couple more small interface improvements and a bunch of little fixes. This should hopefully be the final patch for v3.2 as I move on to early work on the next update!")); changes.addButton(new ChangeButton(Icons.get(Icons.DISPLAY), "Interface Changes", "Two additions have been made to the game's UI:\n" +