diff --git a/core/src/main/assets/interfaces/icons.png b/core/src/main/assets/interfaces/icons.png index eca3d78f7..4c9fcddc5 100644 Binary files a/core/src/main/assets/interfaces/icons.png and b/core/src/main/assets/interfaces/icons.png differ 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 2ba285f78..046f17ed6 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/AboutScene.java @@ -23,129 +23,196 @@ package com.shatteredpixel.shatteredpixeldungeon.scenes; import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.effects.Flare; -import com.shatteredpixel.shatteredpixeldungeon.ui.Archs; import com.shatteredpixel.shatteredpixeldungeon.ui.ExitButton; import com.shatteredpixel.shatteredpixeldungeon.ui.Icons; import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock; +import com.shatteredpixel.shatteredpixeldungeon.ui.ScrollPane; import com.shatteredpixel.shatteredpixeldungeon.ui.Window; import com.watabou.input.PointerEvent; import com.watabou.noosa.Camera; +import com.watabou.noosa.ColorBlock; +import com.watabou.noosa.Group; import com.watabou.noosa.Image; import com.watabou.noosa.PointerArea; +import com.watabou.noosa.ui.Component; import com.watabou.utils.DeviceCompat; public class AboutScene extends PixelScene { - private static final String TTL_SHPX = "Shattered Pixel Dungeon"; - - private static final String TXT_SHPX = - "Design, Code, & Graphics: Evan"; - - private static final String LNK_SHPX = "ShatteredPixel.com"; - - private static final String TTL_WATA = "Pixel Dungeon"; - - private static final String TXT_WATA = - "Code & Graphics: Watabou\n" + - "Music: Cube_Code"; - - private static final String LNK_WATA = "pixeldungeon.watabou.ru"; - @Override public void create() { super.create(); - final float colWidth = Camera.main.width / (landscape() ? 2 : 1); - final float colTop = (Camera.main.height / 2) - (landscape() ? 30 : 90); - final float wataOffset = landscape() ? colWidth : 0; + final float colWidth = 120; + final float fullWidth = colWidth * (landscape() ? 2 : 1); - Image shpx = Icons.SHPX.get(); - shpx.x = (colWidth - shpx.width()) / 2; - shpx.y = colTop; - align(shpx); - add( shpx ); + int w = Camera.main.width; + int h = Camera.main.height; - new Flare( 7, 64 ).color( 0x225511, true ).show( shpx, 0 ).angularSpeed = +20; + ScrollPane list = new ScrollPane( new Component() ); + add( list ); - RenderedTextBlock shpxtitle = renderTextBlock( TTL_SHPX, 8 ); - shpxtitle.hardlight( Window.SHPX_COLOR ); - add( shpxtitle ); + Component content = list.content(); + content.clear(); - shpxtitle.setPos( - (colWidth - shpxtitle.width()) / 2, - shpx.y + shpx.height + 5 - ); - align(shpxtitle); + //*** Shattered Pixel Dungeon Credits *** - RenderedTextBlock shpxtext = renderTextBlock( TXT_SHPX, 8 ); - shpxtext.maxWidth((int)Math.min(colWidth, 120)); - add( shpxtext ); + CreditsBlock shpx = new CreditsBlock(true, Window.SHPX_COLOR, + "Shattered Pixel Dungeon", + Icons.SHPX.get(), + "Developed by: _Evan Debenham_\nBased on Pixel Dungeon's open source", + "ShatteredPixel.com", + "https://ShatteredPixel.com"); + shpx.setRect((w - fullWidth)/2f, 6, 120, 0); + content.add(shpx); - shpxtext.setPos((colWidth - shpxtext.width()) / 2, shpxtitle.bottom() + 12); - align(shpxtext); + CreditsBlock alex = new CreditsBlock(false, Window.SHPX_COLOR, + "Hero Art & Design:", + Icons.ALEKS.get(), + "Aleksandar Komitov", + "alekskomitov.com", + "https://www.alekskomitov.com"); + alex.setSize(colWidth/2f, 0); + if (landscape()){ + alex.setPos(shpx.right(), shpx.top() + (shpx.height() - alex.height())/2f); + } else { + alex.setPos(w/2f - colWidth/2f, shpx.bottom()+5); + } + content.add(alex); - RenderedTextBlock shpxlink = renderTextBlock( LNK_SHPX, 8 ); - shpxlink.maxWidth(shpxtext.maxWidth()); - shpxlink.hardlight( Window.SHPX_COLOR ); - add( shpxlink ); + CreditsBlock charlie = new CreditsBlock(false, Window.SHPX_COLOR, + "Sound Effects:", + Icons.CHARLIE.get(), + "Charlie", + "s9menine.itch.io", + "https://s9menine.itch.io"); + charlie.setRect(alex.right(), alex.top(), colWidth/2f, 0); + content.add(charlie); - shpxlink.setPos((colWidth - shpxlink.width()) / 2, shpxtext.bottom() + 6); - align(shpxlink); + //*** Pixel Dungeon Credits *** - PointerArea shpxhotArea = new PointerArea( shpxlink.left(), shpxlink.top(), shpxlink.width(), shpxlink.height() ) { - @Override - protected void onClick( PointerEvent event ) { - DeviceCompat.openURI( "https://" + LNK_SHPX ); - } - }; - add( shpxhotArea ); + final int WATA_COLOR = 0x55AAFF; + CreditsBlock wata = new CreditsBlock(true, WATA_COLOR, + "Pixel Dungeon", + Icons.WATA.get(), + "Developed by: _Watabou_\nInspired by Brian Walker's Brogue", + "pixeldungeon.watabou.ru", + "http://pixeldungeon.watabou.ru"); + if (landscape()){ + wata.setRect(shpx.left(), shpx.bottom() + 8, colWidth, 0); + } else { + wata.setRect(shpx.left(), alex.bottom() + 8, colWidth, 0); + } + content.add(wata); - Image wata = Icons.WATA.get(); - wata.x = wataOffset + (colWidth - wata.width()) / 2; - wata.y = landscape() ? colTop: shpxlink.top() + wata.height + 20; - align(wata); - add( wata ); + addLine(wata.top() - 4, content); - new Flare( 7, 64 ).color( 0x112233, true ).show( wata, 0 ).angularSpeed = +20; + CreditsBlock cube = new CreditsBlock(false, WATA_COLOR, + "Music:", + Icons.CUBE_CODE.get(), + "Cube Code", + null, + null); + cube.setSize(colWidth/2f, 0); + if (landscape()){ + cube.setPos(wata.right(), wata.top() + (wata.height() - cube.height())/2f); + } else { + cube.setPos(alex.left(), wata.bottom()+5); + } + content.add(cube); - RenderedTextBlock wataTitle = renderTextBlock( TTL_WATA, 8 ); - wataTitle.hardlight(Window.TITLE_COLOR); - add( wataTitle ); + //*** LibGDX Credits *** - wataTitle.setPos( - wataOffset + (colWidth - wataTitle.width()) / 2, - wata.y + wata.height + 11 - ); - align(wataTitle); + final int GDX_COLOR = 0xE44D3C; + CreditsBlock gdx = new CreditsBlock(true, + GDX_COLOR, + null, + Icons.LIBGDX.get(), + "ShatteredPD is powered by _LibGDX_!", + "libgdx.badlogicgames.com", + "http://libgdx.badlogicgames.com"); + if (landscape()){ + gdx.setRect(wata.left(), wata.bottom() + 8, colWidth, 0); + } else { + gdx.setRect(wata.left(), cube.bottom() + 8, colWidth, 0); + } + content.add(gdx); - RenderedTextBlock wataText = renderTextBlock( TXT_WATA, 8 ); - wataText.maxWidth((int)Math.min(colWidth, 120)); - wataText.setHightlighting(false); //underscore in cube_code - add( wataText ); + addLine(gdx.top() - 4, content); - wataText.setPos(wataOffset + (colWidth - wataText.width()) / 2, wataTitle.bottom() + 12); - align(wataText); - - RenderedTextBlock wataLink = renderTextBlock( LNK_WATA, 8 ); - wataLink.maxWidth((int)Math.min(colWidth, 120)); - wataLink.hardlight(Window.TITLE_COLOR); - add(wataLink); - - wataLink.setPos(wataOffset + (colWidth - wataLink.width()) / 2 , wataText.bottom() + 6); - align(wataLink); - - PointerArea hotArea = new PointerArea( wataLink.left(), wataLink.top(), wataLink.width(), wataLink.height() ) { - @Override - protected void onClick( PointerEvent event ) { - DeviceCompat.openURI( "http://" + LNK_WATA ); - } - }; - add( hotArea ); + //blocks the rays from the LibGDX icon going above the line + ColorBlock blocker = new ColorBlock(w, 8, 0xFF000000); + blocker.y = gdx.top() - 12; + content.addToBack(blocker); + content.sendToBack(gdx); - - Archs archs = new Archs(); - archs.setSize( Camera.main.width, Camera.main.height ); - addToBack( archs ); + CreditsBlock arcnor = new CreditsBlock(false, GDX_COLOR, + "Pixel Dungeon GDX:", + Icons.ARCNOR.get(), + "Edu GarcĂ­a", + "twitter.com/arcnor", + "https://twitter.com/arcnor"); + arcnor.setSize(colWidth/2f, 0); + if (landscape()){ + arcnor.setPos(gdx.right(), gdx.top() + (gdx.height() - arcnor.height())/2f); + } else { + arcnor.setPos(alex.left(), gdx.bottom()+5); + } + content.add(arcnor); + + CreditsBlock purigro = new CreditsBlock(false, GDX_COLOR, + "Shattered GDX Help:", + Icons.PURIGRO.get(), + "Kevin MacMartin", + "github.com/prurigro", + "https://github.com/prurigro/"); + purigro.setRect(arcnor.right()+2, arcnor.top(), colWidth/2f, 0); + content.add(purigro); + + //*** Transifex Credits *** + + CreditsBlock transifex = new CreditsBlock(true, + Window.TITLE_COLOR, + null, + null, + "ShatteredPD is community-translated via _Transifex_! Thank you so much to all of Shattered's volunteer translators!", + "www.transifex.com/shattered-pixel/", + "https://www.transifex.com/shattered-pixel/shattered-pixel-dungeon/"); + transifex.setRect((Camera.main.width - colWidth)/2f, purigro.bottom() + 8, colWidth, 0); + content.add(transifex); + + addLine(transifex.top() - 4, content); + + addLine(transifex.bottom() + 4, content); + + //*** Freesound Credits *** + + CreditsBlock freesound = new CreditsBlock(true, + Window.TITLE_COLOR, + null, + null, + "Shattered Pixel Dungeon uses the following sound samples from _freesound.org_:\n" + + "_-_ TBD by TBD\n" + + "_-_ TBD by TBD\n" + + "_-_ TBD by TBD\n" + + "_-_ TBD by TBD\n" + + "_-_ TBD by TBD\n" + + "_-_ TBD by TBD\n" + + "_-_ TBD by TBD\n" + + "_-_ TBD by TBD\n" + + "_-_ TBD by TBD\n" + + "_-_ TBD by TBD\n" + + "_-_ TBD by TBD\n" + + "_-_ TBD by TBD", + null, + null); + freesound.setRect(transifex.left(), transifex.bottom() + 8, colWidth, 0); + content.add(freesound); + + content.setSize( fullWidth, freesound.bottom() ); + + list.setRect( 0, 0, w, h ); + list.scrollTo(0, 0); ExitButton btnExit = new ExitButton(); btnExit.setPos( Camera.main.width - btnExit.width(), 0 ); @@ -156,6 +223,150 @@ public class AboutScene extends PixelScene { @Override protected void onBackPressed() { - ShatteredPixelDungeon.switchNoFade(TitleScene.class); + ShatteredPixelDungeon.switchScene(TitleScene.class); + } + + private void addLine( float y, Group content ){ + ColorBlock line = new ColorBlock(Camera.main.width, 1, 0xFF333333); + line.y = y; + content.add(line); + } + + private static class CreditsBlock extends Component { + + boolean large; + RenderedTextBlock title; + Image avatar; + Flare flare; + RenderedTextBlock body; + + RenderedTextBlock link; + ColorBlock linkUnderline; + PointerArea linkButton; + + //many elements can be null, but body is assumed to have content. + private CreditsBlock(boolean large, int highlight, String title, Image avatar, String body, String linkText, String linkUrl){ + super(); + + this.large = large; + + if (title != null) { + this.title = PixelScene.renderTextBlock(title, large ? 8 : 6); + if (highlight != -1) this.title.hardlight(highlight); + add(this.title); + } + + if (avatar != null){ + this.avatar = avatar; + add(this.avatar); + } + + if (large && highlight != -1 && this.avatar != null){ + this.flare = new Flare( 7, 24 ).color( highlight, true ).show(this.avatar, 0); + this.flare.angularSpeed = 20; + } + + this.body = PixelScene.renderTextBlock(body, 6); + if (highlight != -1) this.body.setHightlighting(true, highlight); + if (large) this.body.align(RenderedTextBlock.CENTER_ALIGN); + add(this.body); + + if (linkText != null && linkUrl != null){ + + int color = 0xFFFFFFFF; + if (highlight != -1) color = 0xFF000000 | highlight; + this.linkUnderline = new ColorBlock(1, 1, color); + add(this.linkUnderline); + + this.link = PixelScene.renderTextBlock(linkText, 6); + if (highlight != -1) this.link.hardlight(highlight); + add(this.link); + + linkButton = new PointerArea(0, 0, 0, 0){ + @Override + protected void onClick( PointerEvent event ) { + DeviceCompat.openURI( linkUrl ); + } + }; + add(linkButton); + } + + } + + @Override + protected void layout() { + super.layout(); + + float topY = top(); + + if (title != null){ + title.maxWidth((int)width()); + title.setPos( x + (width() - title.width())/2f, topY); + topY += title.height() + (large ? 2 : 1); + } + + if (large){ + + if (avatar != null){ + avatar.x = x + (width()-avatar.width())/2f; + avatar.y = topY; + PixelScene.align(avatar); + if (flare != null){ + flare.point(avatar.center()); + } + topY = avatar.y + avatar.height() + 2; + } + + body.maxWidth((int)width()); + body.setPos( x + (width() - body.width())/2f, topY); + topY += body.height() + 2; + + } else { + + if (avatar != null){ + avatar.x = x; + body.maxWidth((int)(width() - avatar.width - 1)); + + if (avatar.height() > body.height()){ + avatar.y = topY; + body.setPos( avatar.x + avatar.width() + 1, topY + (avatar.height() - body.height())/2f); + topY += avatar.height() + 1; + } else { + avatar.y = topY + (body.height() - avatar.height())/2f; + PixelScene.align(avatar); + body.setPos( avatar.x + avatar.width() + 1, topY); + topY += body.height() + 2; + } + + } else { + topY += 1; + body.maxWidth((int)width()); + body.setPos( x, topY); + topY += body.height()+2; + } + + } + + if (link != null){ + if (large) topY += 1; + link.maxWidth((int)width()); + link.setPos( x + (width() - link.width())/2f, topY); + topY += link.height() + 2; + + linkButton.x = link.left()-1; + linkButton.y = link.top()-1; + linkButton.width = link.width()+2; + linkButton.height = link.height()+2; + + linkUnderline.size(link.width(), PixelScene.align(0.49f)); + linkUnderline.x = link.left(); + linkUnderline.y = link.bottom()+1; + + } + + topY -= 2; + + height = Math.max(height, topY - top()); + } } } 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 54f78ae83..091ebf832 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/TitleScene.java @@ -174,7 +174,7 @@ public class TitleScene extends PixelScene { TitleButton btnAbout = new TitleButton(Messages.get(this, "about")){ @Override protected void onClick() { - ShatteredPixelDungeon.switchNoFade( AboutScene.class ); + ShatteredPixelDungeon.switchScene( AboutScene.class ); } }; btnAbout.icon(Icons.get(Icons.SHPX)); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Icons.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Icons.java index 4e404bda4..0b7f93e59 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Icons.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/Icons.java @@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.ui; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass; +import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; import com.watabou.noosa.Image; public enum Icons { @@ -71,7 +72,14 @@ public enum Icons { //misc icons LIBGDX, WATA, - WARNING; + WARNING, + + //32x32 icons for credits + CUBE_CODE, + PURIGRO, + ARCNOR, + ALEKS, + CHARLIE; public Image get() { return get( this ); @@ -192,6 +200,29 @@ public enum Icons { case WARNING: icon.frame( icon.texture.uvRect( 34, 81, 48, 95 ) ); break; + + //32*32 icons are scaled down to match game's size + case ALEKS: + icon.frame( icon.texture.uvRect( 0, 96, 32, 128 ) ); + icon.scale.set(PixelScene.align(0.49f)); + break; + case CHARLIE: + icon.frame( icon.texture.uvRect( 32, 96, 64, 128 ) ); + icon.scale.set(PixelScene.align(0.49f)); + break; + case ARCNOR: + icon.frame( icon.texture.uvRect( 64, 96, 96, 128 ) ); + icon.scale.set(PixelScene.align(0.49f)); + break; + case PURIGRO: + icon.frame( icon.texture.uvRect( 96, 96, 128, 128 ) ); + icon.scale.set(PixelScene.align(0.49f)); + break; + case CUBE_CODE: + icon.frame( icon.texture.uvRect( 101, 39, 128, 69 ) ); + icon.scale.set(PixelScene.align(0.49f)); + break; + } return icon; } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/RenderedTextBlock.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/RenderedTextBlock.java index dfa524f41..1b7ead2ab 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/RenderedTextBlock.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/RenderedTextBlock.java @@ -211,7 +211,7 @@ public class RenderedTextBlock extends Component { } else { if (word.height() > height) height = word.height(); - if ((x - this.x) + word.width() > maxWidth){ + if ((x - this.x) + word.width() > maxWidth && !curLine.isEmpty()){ y += height+2f; x = this.x; nLines++;