From a32a5239313ff87f0d190fe494ea04ffb158c284 Mon Sep 17 00:00:00 2001 From: Alexis King Date: Sat, 1 Oct 2022 18:00:36 -0500 Subject: [PATCH] Initial public commit --- .gitignore | 3 + README.md | 50 + docs/cache.md | 45 + docs/screenshot.png | Bin 0 -> 397883 bytes pom.xml | 122 + src/main/java/funorb/Strings.java | 441 ++ src/main/java/funorb/audio/AudioThread.java | 38 + src/main/java/funorb/audio/MusicTrack.java | 408 ++ src/main/java/funorb/audio/PlayingSound.java | 19 + .../funorb/audio/SampledAudioChannel.java | 345 ++ src/main/java/funorb/audio/SoundEffect.java | 21 + src/main/java/funorb/audio/SoundLoader.java | 99 + src/main/java/funorb/audio/al_.java | 1110 ++++ src/main/java/funorb/audio/br_.java | 490 ++ src/main/java/funorb/audio/dq_.java | 69 + src/main/java/funorb/audio/fd_.java | 598 ++ src/main/java/funorb/audio/fh_.java | 119 + src/main/java/funorb/audio/fq_.java | 31 + src/main/java/funorb/audio/ga_.java | 843 +++ src/main/java/funorb/audio/h_.java | 243 + src/main/java/funorb/audio/kc_.java | 13 + src/main/java/funorb/audio/kk_.java | 22 + src/main/java/funorb/audio/kn_.java | 286 + src/main/java/funorb/audio/pi_.java | 200 + src/main/java/funorb/audio/pk_.java | 312 ++ src/main/java/funorb/audio/pn_.java | 65 + src/main/java/funorb/audio/qq_.java | 34 + src/main/java/funorb/audio/rc_.java | 147 + src/main/java/funorb/audio/tn_.java | 30 + src/main/java/funorb/audio/to_.java | 106 + src/main/java/funorb/audio/vb_.java | 232 + src/main/java/funorb/audio/vk_.java | 38 + .../java/funorb/awt/CanvasScreenBuffer.java | 35 + src/main/java/funorb/awt/ComponentCanvas.java | 23 + .../java/funorb/awt/FullScreenCanvas.java | 35 + src/main/java/funorb/awt/GraphicsBackend.java | 87 + .../funorb/awt/ImageProducerScreenBuffer.java | 79 + src/main/java/funorb/awt/KeyState.java | 326 ++ .../java/funorb/awt/MouseControlBackend.java | 48 + src/main/java/funorb/awt/MouseState.java | 164 + src/main/java/funorb/awt/MouseWheelState.java | 30 + src/main/java/funorb/awt/ScreenBuffer.java | 22 + .../java/funorb/cache/BufferedCacheFile.java | 158 + .../java/funorb/cache/BufferedPageCache.java | 250 + src/main/java/funorb/cache/CacheFile.java | 110 + src/main/java/funorb/cache/CacheWorker.java | 159 + .../java/funorb/cache/LocalPageSource.java | 33 + .../java/funorb/cache/MasterIndexLoader.java | 85 + src/main/java/funorb/cache/PageIndex.java | 209 + src/main/java/funorb/cache/PageLoader.java | 272 + src/main/java/funorb/cache/PageSource.java | 55 + .../java/funorb/cache/RemotePageSource.java | 252 + .../java/funorb/cache/ResourceDirectory.java | 57 + .../java/funorb/cache/ResourceLoader.java | 472 ++ .../funorb/client/AchievementRequest.java | 7 + src/main/java/funorb/client/DisplayMode.java | 7 + .../funorb/client/EmailLoginCredentials.java | 36 + .../java/funorb/client/GetProfileRequest.java | 6 + .../java/funorb/client/JagexBaseApplet.java | 328 ++ .../java/funorb/client/LoginCredentials.java | 13 + src/main/java/funorb/client/LoginState.java | 15 + .../java/funorb/client/MenuInputState.java | 129 + .../java/funorb/client/RankingsRequest.java | 13 + .../java/funorb/client/ReflectionRequest.java | 125 + .../java/funorb/client/SetProfileRequest.java | 10 + .../funorb/client/TemplateDictionary.java | 84 + .../funorb/client/UserIdLoginCredentials.java | 74 + src/main/java/funorb/client/e_.java | 31 + .../client/intro/JagexLogoIntroAnimation.java | 1325 +++++ src/main/java/funorb/client/intro/hc_.java | 5 + src/main/java/funorb/client/intro/sr_.java | 110 + src/main/java/funorb/client/li_.java | 15 + .../funorb/client/lobby/ActionButton.java | 88 + .../client/lobby/AddOrRemovePlayerPopup.java | 190 + .../java/funorb/client/lobby/ChatMessage.java | 119 + .../java/funorb/client/lobby/Checkbox.java | 45 + .../funorb/client/lobby/ClientLobbyRoom.java | 568 ++ .../java/funorb/client/lobby/Component.java | 1530 +++++ .../java/funorb/client/lobby/ContextMenu.java | 446 ++ .../java/funorb/client/lobby/LobbyPlayer.java | 86 + .../java/funorb/client/lobby/PlayerList.java | 49 + .../funorb/client/lobby/PlayerListEntry.java | 256 + .../java/funorb/client/lobby/PopupMenu.java | 143 + .../client/lobby/QuickChatCategories.java | 36 + .../client/lobby/QuickChatCategory.java | 63 + .../client/lobby/QuickChatHelpPanel.java | 63 + .../client/lobby/QuickChatResponse.java | 59 + .../client/lobby/QuickChatResponses.java | 36 + .../client/lobby/ReportAbuseDialog.java | 273 + .../java/funorb/client/lobby/ScrollBar.java | 211 + .../java/funorb/client/lobby/ScrollPane.java | 95 + .../funorb/client/lobby/TabbedPlayerList.java | 75 + .../client/lobby/TabbedPlayerListWrapper.java | 22 + src/main/java/funorb/client/lobby/vm_.java | 239 + src/main/java/funorb/client/pa_.java | 69 + src/main/java/funorb/client/r_.java | 174 + .../funorb/commonui/AbstractTextField.java | 359 ++ .../funorb/commonui/AbstractTextLayout.java | 109 + .../java/funorb/commonui/AccountPage.java | 133 + src/main/java/funorb/commonui/Button.java | 195 + src/main/java/funorb/commonui/Checkbox.java | 23 + src/main/java/funorb/commonui/CommonUI.java | 289 + src/main/java/funorb/commonui/Component.java | 229 + .../funorb/commonui/CreateAccountPage.java | 123 + src/main/java/funorb/commonui/Enum1.java | 5 + .../funorb/commonui/FormNavigationPage.java | 129 + .../funorb/commonui/FramedNavigationPage.java | 177 + src/main/java/funorb/commonui/LoadingBar.java | 60 + .../java/funorb/commonui/NavigationPage.java | 85 + .../java/funorb/commonui/NavigationRoot.java | 68 + .../java/funorb/commonui/ProgressBar.java | 150 + src/main/java/funorb/commonui/Resources.java | 87 + src/main/java/funorb/commonui/TextLayout.java | 139 + .../java/funorb/commonui/TextLineMetrics.java | 58 + .../java/funorb/commonui/TooltipManager.java | 134 + src/main/java/funorb/commonui/ah_.java | 94 + src/main/java/funorb/commonui/cf_.java | 79 + src/main/java/funorb/commonui/cg_.java | 35 + .../commonui/container/ArrayContainer.java | 227 + .../funorb/commonui/container/Container.java | 4 + .../commonui/container/ListContainer.java | 157 + .../commonui/container/WrapperContainer.java | 142 + .../commonui/form/CreateAccountForm.java | 251 + .../commonui/form/CreateDisplayNameForm.java | 132 + .../java/funorb/commonui/form/CreateForm.java | 6 + .../commonui/form/CreateFormListener.java | 84 + .../commonui/form/DobToEnableChatForm.java | 68 + .../funorb/commonui/form/JustPlayForm.java | 71 + .../java/funorb/commonui/form/LoginForm.java | 207 + .../form/field/AbstractDateField.java | 31 + .../funorb/commonui/form/field/DateField.java | 125 + .../commonui/form/field/InputField.java | 7 + .../funorb/commonui/form/field/TextField.java | 56 + .../validator/AbstractInputValidator.java | 34 + .../commonui/form/validator/AgeValidator.java | 26 + .../form/validator/ConfirmEmailValidator.java | 53 + .../validator/ConfirmPasswordValidator.java | 43 + .../form/validator/DateOfBirthValidator.java | 108 + .../form/validator/EmailValidator.java | 163 + .../form/validator/InputValidator.java | 11 + .../form/validator/PasswordValidator.java | 181 + .../form/validator/StringValidator.java | 40 + .../form/validator/UsernameValidator.java | 185 + .../form/validator/ValidationState.java | 5 + src/main/java/funorb/commonui/g_.java | 4 + src/main/java/funorb/commonui/hl_.java | 63 + src/main/java/funorb/commonui/kj_.java | 13 + src/main/java/funorb/commonui/ks_.java | 28 + .../commonui/listener/ButtonListener.java | 7 + .../commonui/listener/ComponentListener.java | 4 + .../commonui/listener/TextFieldListener.java | 8 + src/main/java/funorb/commonui/op_.java | 5 + src/main/java/funorb/commonui/pe_.java | 71 + src/main/java/funorb/commonui/pg_.java | 61 + src/main/java/funorb/commonui/ql_.java | 18 + .../commonui/renderer/ButtonRenderer.java | 49 + .../commonui/renderer/CheckboxRenderer.java | 23 + .../commonui/renderer/ComponentRenderer.java | 22 + .../commonui/renderer/ITextRenderer.java | 26 + .../commonui/renderer/LinkRenderer.java | 51 + .../renderer/PasswordFieldRenderer.java | 27 + .../commonui/renderer/TextFieldRenderer.java | 23 + .../commonui/renderer/TextRenderer.java | 235 + src/main/java/funorb/commonui/ts_.java | 148 + src/main/java/funorb/data/LRUCache.java | 17 + src/main/java/funorb/data/NodeList.java | 157 + src/main/java/funorb/graphics/ArgbSprite.java | 1228 ++++ src/main/java/funorb/graphics/Drawing.java | 2132 +++++++ src/main/java/funorb/graphics/Font.java | 846 +++ .../java/funorb/graphics/NineSliceSprite.java | 123 + .../funorb/graphics/PalettedSpriteFont.java | 298 + .../java/funorb/graphics/PalettedSymbol.java | 189 + src/main/java/funorb/graphics/Point.java | 11 + src/main/java/funorb/graphics/Rect.java | 28 + src/main/java/funorb/graphics/Sprite.java | 2153 +++++++ src/main/java/funorb/graphics/SpriteFont.java | 315 ++ .../java/funorb/graphics/SpriteResource.java | 189 + src/main/java/funorb/graphics/Symbol.java | 14 + src/main/java/funorb/graphics/mq_.java | 35 + .../funorb/graphics/vector/RasterSpan.java | 40 + .../funorb/graphics/vector/VectorDrawing.java | 395 ++ src/main/java/funorb/io/Buffer.java | 516 ++ src/main/java/funorb/io/ByteContainer.java | 5 + src/main/java/funorb/io/Bzip2.java | 448 ++ src/main/java/funorb/io/CipheredBuffer.java | 64 + .../java/funorb/io/DirectByteContainer.java | 21 + src/main/java/funorb/io/DuplexStream.java | 196 + src/main/java/funorb/io/HuffmanCoder.java | 305 + src/main/java/funorb/io/Inflater.java | 21 + src/main/java/funorb/io/Packet.java | 209 + src/main/java/funorb/io/PacketLengthType.java | 16 + src/main/java/funorb/io/ReadableBuffer.java | 39 + src/main/java/funorb/io/WritableBuffer.java | 43 + .../java/funorb/net/ProtocolException.java | 23 + .../java/funorb/shatteredplans/C2SPacket.java | 280 + .../funorb/shatteredplans/CacheFiles.java | 39 + .../java/funorb/shatteredplans/S2CPacket.java | 220 + .../shatteredplans/StringConstants.java | 1517 +++++ .../client/AchievementNotification.java | 9 + .../shatteredplans/client/AuthMode.java | 15 + .../CombatEngagementAnimationState.java | 56 + .../shatteredplans/client/FrameClock.java | 69 + .../funorb/shatteredplans/client/GameUI.java | 3269 +++++++++++ .../shatteredplans/client/JagexApplet.java | 2545 +++++++++ .../shatteredplans/client/MailboxMessage.java | 59 + .../funorb/shatteredplans/client/Menu.java | 3159 +++++++++++ .../client/MessagePumpThread.java | 314 ++ .../shatteredplans/client/RenderQuality.java | 40 + .../client/ShatteredPlansClient.java | 4972 +++++++++++++++++ .../funorb/shatteredplans/client/Sounds.java | 99 + .../client/TutorialMessage.java | 69 + .../client/TutorialMessageId.java | 9 + .../client/TutorialMessages.java | 183 + .../client/game/AbstractGameView.java | 604 ++ .../client/game/BuildEvent.java | 31 + .../client/game/BuildFleetsEvent.java | 16 + .../client/game/ClientGameSession.java | 1895 +++++++ .../client/game/CombatEngagementLog.java | 47 + .../client/game/CombatExplosion.java | 25 + .../client/game/CombatLogEvent.java | 29 + .../client/game/FleetRetreatEvent.java | 20 + .../shatteredplans/client/game/GameView.java | 3701 ++++++++++++ .../client/game/MoveFleetsAnimationState.java | 19 + .../client/game/PlayerStats.java | 97 + .../client/game/StellarBombEvent.java | 16 + .../shatteredplans/client/game/TickTimer.java | 19 + .../client/game/TurnEventLog.java | 71 + .../client/game/TutorialObjective.java | 6 + .../client/game/TutorialState.java | 1082 ++++ .../client/intro/IntroAnimation.java | 1248 +++++ .../client/intro/RenderedTextLine.java | 44 + .../shatteredplans/client/intro/nd_.java | 15 + .../shatteredplans/client/intro/sb_.java | 34 + .../shatteredplans/client/ui/Button.java | 72 + .../shatteredplans/client/ui/ChatMessage.java | 40 + .../client/ui/DiplomacyPanelState.java | 16 + .../shatteredplans/client/ui/FixedPanel.java | 62 + .../client/ui/FloatingPanel.java | 215 + .../funorb/shatteredplans/client/ui/Icon.java | 37 + .../shatteredplans/client/ui/Label.java | 33 + .../client/ui/MultilineLabel.java | 30 + .../shatteredplans/client/ui/PanelState.java | 4 + .../client/ui/ProductionPanelState.java | 62 + .../client/ui/ProjectsPanelState.java | 8 + .../shatteredplans/client/ui/RoundedRect.java | 25 + .../shatteredplans/client/ui/ScrollBar.java | 80 + .../client/ui/ScrollBarListener.java | 7 + .../shatteredplans/client/ui/ScrollView.java | 74 + .../client/ui/StatusPanelState.java | 6 + .../shatteredplans/client/ui/UIComponent.java | 102 + .../funorb/shatteredplans/client/ui/fe_.java | 43 + .../funorb/shatteredplans/client/ui/kb_.java | 67 + .../funorb/shatteredplans/client/ui/uc_.java | 24 + .../shatteredplans/game/BuildFleetsOrder.java | 38 + .../shatteredplans/game/CombinedForce.java | 18 + .../shatteredplans/game/ContiguousForce.java | 28 + .../funorb/shatteredplans/game/Force.java | 86 + .../shatteredplans/game/GameOptions.java | 77 + .../shatteredplans/game/GameSession.java | 37 + .../funorb/shatteredplans/game/GameState.java | 1876 +++++++ .../shatteredplans/game/MoveFleetsOrder.java | 53 + .../funorb/shatteredplans/game/Player.java | 85 + .../shatteredplans/game/ProjectOrder.java | 56 + .../shatteredplans/game/TurnOrders.java | 101 + .../funorb/shatteredplans/game/ai/AI.java | 36 + .../funorb/shatteredplans/game/ai/AITask.java | 14 + .../shatteredplans/game/ai/CaptureTask.java | 120 + .../shatteredplans/game/ai/DefenseTask.java | 37 + .../shatteredplans/game/ai/HoldTask.java | 17 + .../funorb/shatteredplans/game/ai/TaskAI.java | 1804 ++++++ .../shatteredplans/game/ai/TutorialAI1.java | 1350 +++++ .../shatteredplans/game/ai/TutorialAI2.java | 99 + .../shatteredplans/game/ai/TutorialAI3.java | 119 + .../map/CaptureAndHoldVictoryChecker.java | 189 + .../map/ConquestVictoryChecker.java | 35 + .../map/DerelictsVictoryChecker.java | 186 + .../java/funorb/shatteredplans/map/Map.java | 409 ++ .../map/PointsVictoryChecker.java | 189 + .../funorb/shatteredplans/map/StarSystem.java | 242 + .../shatteredplans/map/TannhauserLink.java | 21 + .../map/TannhauserUnconnectedException.java | 7 + .../map/TutorialVictoryChecker.java | 99 + .../shatteredplans/map/VictoryChecker.java | 66 + .../generator/CaptureAndHoldMapGenerator.java | 112 + .../generator/CaptureAndHoldMapReader.java | 64 + .../map/generator/DerelictsMapGenerator.java | 91 + .../map/generator/DerelictsMapReader.java | 77 + .../map/generator/MapGenerationFailure.java | 7 + .../map/generator/MapGenerator.java | 10 + .../map/generator/StandardMapGenerator.java | 597 ++ .../map/generator/StandardMapReader.java | 66 + .../map/generator/TutorialMapGenerator.java | 420 ++ .../map/generator/WormholeConnection.java | 91 + .../server/ClientConnection.java | 49 + .../shatteredplans/server/ClientHandler.java | 280 + .../shatteredplans/server/ClientPlayer.java | 86 + .../shatteredplans/server/LobbyRoom.java | 369 ++ .../shatteredplans/server/LobbyState.java | 119 + .../server/NetworkedGameSession.java | 392 ++ .../server/ResourceStreamInput.java | 88 + .../server/ShatteredPlansServer.java | 290 + src/main/java/funorb/util/ArrayUtil.java | 115 + src/main/java/funorb/util/BitMath.java | 45 + src/main/java/funorb/util/CollectionUtil.java | 43 + src/main/java/funorb/util/Functions.java | 10 + .../funorb/util/IntToBooleanFunction.java | 6 + src/main/java/funorb/util/IsaacCipher.java | 176 + src/main/java/funorb/util/IsaacRandom.java | 26 + src/main/java/funorb/util/MathUtil.java | 68 + .../funorb/util/PseudoMonotonicClock.java | 16 + src/main/java/funorb/util/Whirlpool.java | 263 + .../java/launcher/CommandLineOptions.java | 87 + .../java/launcher/ShatteredPlansLauncher.java | 218 + src/main/java/launcher/app/FOContext.java | 108 + src/main/java/launcher/app/FOEventQueue.java | 83 + src/main/java/launcher/app/FOStub.java | 143 + src/main/java/launcher/app/JFocusFrame.java | 27 + src/main/java/launcher/db/DBUtils.java | 101 + src/main/java/launcher/db/Database.java | 115 + .../java/launcher/db/DatabasePromise.java | 167 + src/main/java/launcher/db/DatabaseTask.java | 5 + .../java/launcher/options/OptionType.java | 5 + .../launcher/options/OptionsDatabase.java | 186 + src/main/java/launcher/util/HEXUtils.java | 88 + .../funorb/shatteredplans/server/boot.sql | 9 + .../shatteredplans/server/res/res_01_0001.dat | Bin 0 -> 12085 bytes .../shatteredplans/server/res/res_01_000B.dat | Bin 0 -> 21649 bytes .../shatteredplans/server/res/res_01_0015.dat | Bin 0 -> 22520 bytes .../shatteredplans/server/res/res_02_000B.dat | Bin 0 -> 282 bytes .../shatteredplans/server/res/res_02_0015.dat | Bin 0 -> 4890 bytes .../shatteredplans/server/res/res_03_0000.dat | Bin 0 -> 119 bytes .../shatteredplans/server/res/res_05_0000.dat | Bin 0 -> 1958793 bytes .../shatteredplans/server/res/res_05_0001.dat | Bin 0 -> 622532 bytes .../shatteredplans/server/res/res_06_0000.dat | Bin 0 -> 210849 bytes .../shatteredplans/server/res/res_07_0000.dat | Bin 0 -> 2187 bytes .../shatteredplans/server/res/res_08_0000.dat | Bin 0 -> 1207 bytes .../shatteredplans/server/res/res_09_0000.dat | Bin 0 -> 553675 bytes .../shatteredplans/server/res/res_0A_0000.dat | Bin 0 -> 869 bytes .../shatteredplans/server/res/res_0B_0000.dat | Bin 0 -> 7120 bytes .../shatteredplans/server/res/res_0C_0000.dat | Bin 0 -> 4545 bytes .../shatteredplans/server/res/res_0D_0000.dat | Bin 0 -> 373 bytes .../shatteredplans/server/res/res_0D_0001.dat | Bin 0 -> 805 bytes .../shatteredplans/server/res/res_0E_0000.dat | Bin 0 -> 1200 bytes .../shatteredplans/server/res/res_0E_0001.dat | Bin 0 -> 2205 bytes .../shatteredplans/server/res/res_0E_0002.dat | Bin 0 -> 20708 bytes .../shatteredplans/server/res/res_0E_0003.dat | Bin 0 -> 9912 bytes .../shatteredplans/server/res/res_0E_0004.dat | Bin 0 -> 56312 bytes .../shatteredplans/server/res/res_FF_0001.dat | Bin 0 -> 805 bytes .../shatteredplans/server/res/res_FF_0002.dat | Bin 0 -> 739 bytes .../shatteredplans/server/res/res_FF_0003.dat | Bin 0 -> 35 bytes .../shatteredplans/server/res/res_FF_0005.dat | Bin 0 -> 615 bytes .../shatteredplans/server/res/res_FF_0006.dat | Bin 0 -> 83 bytes .../shatteredplans/server/res/res_FF_0007.dat | Bin 0 -> 41 bytes .../shatteredplans/server/res/res_FF_0008.dat | Bin 0 -> 113 bytes .../shatteredplans/server/res/res_FF_0009.dat | Bin 0 -> 473 bytes .../shatteredplans/server/res/res_FF_000A.dat | Bin 0 -> 67 bytes .../shatteredplans/server/res/res_FF_000B.dat | Bin 0 -> 59 bytes .../shatteredplans/server/res/res_FF_000C.dat | Bin 0 -> 41 bytes .../shatteredplans/server/res/res_FF_000D.dat | Bin 0 -> 209 bytes .../shatteredplans/server/res/res_FF_000E.dat | Bin 0 -> 123 bytes .../shatteredplans/server/res/res_FF_00FF.dat | Bin 0 -> 1151 bytes src/main/resources/launcher/boot.sql | 15 + 362 files changed, 72723 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 docs/cache.md create mode 100644 docs/screenshot.png create mode 100644 pom.xml create mode 100644 src/main/java/funorb/Strings.java create mode 100644 src/main/java/funorb/audio/AudioThread.java create mode 100644 src/main/java/funorb/audio/MusicTrack.java create mode 100644 src/main/java/funorb/audio/PlayingSound.java create mode 100644 src/main/java/funorb/audio/SampledAudioChannel.java create mode 100644 src/main/java/funorb/audio/SoundEffect.java create mode 100644 src/main/java/funorb/audio/SoundLoader.java create mode 100644 src/main/java/funorb/audio/al_.java create mode 100644 src/main/java/funorb/audio/br_.java create mode 100644 src/main/java/funorb/audio/dq_.java create mode 100644 src/main/java/funorb/audio/fd_.java create mode 100644 src/main/java/funorb/audio/fh_.java create mode 100644 src/main/java/funorb/audio/fq_.java create mode 100644 src/main/java/funorb/audio/ga_.java create mode 100644 src/main/java/funorb/audio/h_.java create mode 100644 src/main/java/funorb/audio/kc_.java create mode 100644 src/main/java/funorb/audio/kk_.java create mode 100644 src/main/java/funorb/audio/kn_.java create mode 100644 src/main/java/funorb/audio/pi_.java create mode 100644 src/main/java/funorb/audio/pk_.java create mode 100644 src/main/java/funorb/audio/pn_.java create mode 100644 src/main/java/funorb/audio/qq_.java create mode 100644 src/main/java/funorb/audio/rc_.java create mode 100644 src/main/java/funorb/audio/tn_.java create mode 100644 src/main/java/funorb/audio/to_.java create mode 100644 src/main/java/funorb/audio/vb_.java create mode 100644 src/main/java/funorb/audio/vk_.java create mode 100644 src/main/java/funorb/awt/CanvasScreenBuffer.java create mode 100644 src/main/java/funorb/awt/ComponentCanvas.java create mode 100644 src/main/java/funorb/awt/FullScreenCanvas.java create mode 100644 src/main/java/funorb/awt/GraphicsBackend.java create mode 100644 src/main/java/funorb/awt/ImageProducerScreenBuffer.java create mode 100644 src/main/java/funorb/awt/KeyState.java create mode 100644 src/main/java/funorb/awt/MouseControlBackend.java create mode 100644 src/main/java/funorb/awt/MouseState.java create mode 100644 src/main/java/funorb/awt/MouseWheelState.java create mode 100644 src/main/java/funorb/awt/ScreenBuffer.java create mode 100644 src/main/java/funorb/cache/BufferedCacheFile.java create mode 100644 src/main/java/funorb/cache/BufferedPageCache.java create mode 100644 src/main/java/funorb/cache/CacheFile.java create mode 100644 src/main/java/funorb/cache/CacheWorker.java create mode 100644 src/main/java/funorb/cache/LocalPageSource.java create mode 100644 src/main/java/funorb/cache/MasterIndexLoader.java create mode 100644 src/main/java/funorb/cache/PageIndex.java create mode 100644 src/main/java/funorb/cache/PageLoader.java create mode 100644 src/main/java/funorb/cache/PageSource.java create mode 100644 src/main/java/funorb/cache/RemotePageSource.java create mode 100644 src/main/java/funorb/cache/ResourceDirectory.java create mode 100644 src/main/java/funorb/cache/ResourceLoader.java create mode 100644 src/main/java/funorb/client/AchievementRequest.java create mode 100644 src/main/java/funorb/client/DisplayMode.java create mode 100644 src/main/java/funorb/client/EmailLoginCredentials.java create mode 100644 src/main/java/funorb/client/GetProfileRequest.java create mode 100644 src/main/java/funorb/client/JagexBaseApplet.java create mode 100644 src/main/java/funorb/client/LoginCredentials.java create mode 100644 src/main/java/funorb/client/LoginState.java create mode 100644 src/main/java/funorb/client/MenuInputState.java create mode 100644 src/main/java/funorb/client/RankingsRequest.java create mode 100644 src/main/java/funorb/client/ReflectionRequest.java create mode 100644 src/main/java/funorb/client/SetProfileRequest.java create mode 100644 src/main/java/funorb/client/TemplateDictionary.java create mode 100644 src/main/java/funorb/client/UserIdLoginCredentials.java create mode 100644 src/main/java/funorb/client/e_.java create mode 100644 src/main/java/funorb/client/intro/JagexLogoIntroAnimation.java create mode 100644 src/main/java/funorb/client/intro/hc_.java create mode 100644 src/main/java/funorb/client/intro/sr_.java create mode 100644 src/main/java/funorb/client/li_.java create mode 100644 src/main/java/funorb/client/lobby/ActionButton.java create mode 100644 src/main/java/funorb/client/lobby/AddOrRemovePlayerPopup.java create mode 100644 src/main/java/funorb/client/lobby/ChatMessage.java create mode 100644 src/main/java/funorb/client/lobby/Checkbox.java create mode 100644 src/main/java/funorb/client/lobby/ClientLobbyRoom.java create mode 100644 src/main/java/funorb/client/lobby/Component.java create mode 100644 src/main/java/funorb/client/lobby/ContextMenu.java create mode 100644 src/main/java/funorb/client/lobby/LobbyPlayer.java create mode 100644 src/main/java/funorb/client/lobby/PlayerList.java create mode 100644 src/main/java/funorb/client/lobby/PlayerListEntry.java create mode 100644 src/main/java/funorb/client/lobby/PopupMenu.java create mode 100644 src/main/java/funorb/client/lobby/QuickChatCategories.java create mode 100644 src/main/java/funorb/client/lobby/QuickChatCategory.java create mode 100644 src/main/java/funorb/client/lobby/QuickChatHelpPanel.java create mode 100644 src/main/java/funorb/client/lobby/QuickChatResponse.java create mode 100644 src/main/java/funorb/client/lobby/QuickChatResponses.java create mode 100644 src/main/java/funorb/client/lobby/ReportAbuseDialog.java create mode 100644 src/main/java/funorb/client/lobby/ScrollBar.java create mode 100644 src/main/java/funorb/client/lobby/ScrollPane.java create mode 100644 src/main/java/funorb/client/lobby/TabbedPlayerList.java create mode 100644 src/main/java/funorb/client/lobby/TabbedPlayerListWrapper.java create mode 100644 src/main/java/funorb/client/lobby/vm_.java create mode 100644 src/main/java/funorb/client/pa_.java create mode 100644 src/main/java/funorb/client/r_.java create mode 100644 src/main/java/funorb/commonui/AbstractTextField.java create mode 100644 src/main/java/funorb/commonui/AbstractTextLayout.java create mode 100644 src/main/java/funorb/commonui/AccountPage.java create mode 100644 src/main/java/funorb/commonui/Button.java create mode 100644 src/main/java/funorb/commonui/Checkbox.java create mode 100644 src/main/java/funorb/commonui/CommonUI.java create mode 100644 src/main/java/funorb/commonui/Component.java create mode 100644 src/main/java/funorb/commonui/CreateAccountPage.java create mode 100644 src/main/java/funorb/commonui/Enum1.java create mode 100644 src/main/java/funorb/commonui/FormNavigationPage.java create mode 100644 src/main/java/funorb/commonui/FramedNavigationPage.java create mode 100644 src/main/java/funorb/commonui/LoadingBar.java create mode 100644 src/main/java/funorb/commonui/NavigationPage.java create mode 100644 src/main/java/funorb/commonui/NavigationRoot.java create mode 100644 src/main/java/funorb/commonui/ProgressBar.java create mode 100644 src/main/java/funorb/commonui/Resources.java create mode 100644 src/main/java/funorb/commonui/TextLayout.java create mode 100644 src/main/java/funorb/commonui/TextLineMetrics.java create mode 100644 src/main/java/funorb/commonui/TooltipManager.java create mode 100644 src/main/java/funorb/commonui/ah_.java create mode 100644 src/main/java/funorb/commonui/cf_.java create mode 100644 src/main/java/funorb/commonui/cg_.java create mode 100644 src/main/java/funorb/commonui/container/ArrayContainer.java create mode 100644 src/main/java/funorb/commonui/container/Container.java create mode 100644 src/main/java/funorb/commonui/container/ListContainer.java create mode 100644 src/main/java/funorb/commonui/container/WrapperContainer.java create mode 100644 src/main/java/funorb/commonui/form/CreateAccountForm.java create mode 100644 src/main/java/funorb/commonui/form/CreateDisplayNameForm.java create mode 100644 src/main/java/funorb/commonui/form/CreateForm.java create mode 100644 src/main/java/funorb/commonui/form/CreateFormListener.java create mode 100644 src/main/java/funorb/commonui/form/DobToEnableChatForm.java create mode 100644 src/main/java/funorb/commonui/form/JustPlayForm.java create mode 100644 src/main/java/funorb/commonui/form/LoginForm.java create mode 100644 src/main/java/funorb/commonui/form/field/AbstractDateField.java create mode 100644 src/main/java/funorb/commonui/form/field/DateField.java create mode 100644 src/main/java/funorb/commonui/form/field/InputField.java create mode 100644 src/main/java/funorb/commonui/form/field/TextField.java create mode 100644 src/main/java/funorb/commonui/form/validator/AbstractInputValidator.java create mode 100644 src/main/java/funorb/commonui/form/validator/AgeValidator.java create mode 100644 src/main/java/funorb/commonui/form/validator/ConfirmEmailValidator.java create mode 100644 src/main/java/funorb/commonui/form/validator/ConfirmPasswordValidator.java create mode 100644 src/main/java/funorb/commonui/form/validator/DateOfBirthValidator.java create mode 100644 src/main/java/funorb/commonui/form/validator/EmailValidator.java create mode 100644 src/main/java/funorb/commonui/form/validator/InputValidator.java create mode 100644 src/main/java/funorb/commonui/form/validator/PasswordValidator.java create mode 100644 src/main/java/funorb/commonui/form/validator/StringValidator.java create mode 100644 src/main/java/funorb/commonui/form/validator/UsernameValidator.java create mode 100644 src/main/java/funorb/commonui/form/validator/ValidationState.java create mode 100644 src/main/java/funorb/commonui/g_.java create mode 100644 src/main/java/funorb/commonui/hl_.java create mode 100644 src/main/java/funorb/commonui/kj_.java create mode 100644 src/main/java/funorb/commonui/ks_.java create mode 100644 src/main/java/funorb/commonui/listener/ButtonListener.java create mode 100644 src/main/java/funorb/commonui/listener/ComponentListener.java create mode 100644 src/main/java/funorb/commonui/listener/TextFieldListener.java create mode 100644 src/main/java/funorb/commonui/op_.java create mode 100644 src/main/java/funorb/commonui/pe_.java create mode 100644 src/main/java/funorb/commonui/pg_.java create mode 100644 src/main/java/funorb/commonui/ql_.java create mode 100644 src/main/java/funorb/commonui/renderer/ButtonRenderer.java create mode 100644 src/main/java/funorb/commonui/renderer/CheckboxRenderer.java create mode 100644 src/main/java/funorb/commonui/renderer/ComponentRenderer.java create mode 100644 src/main/java/funorb/commonui/renderer/ITextRenderer.java create mode 100644 src/main/java/funorb/commonui/renderer/LinkRenderer.java create mode 100644 src/main/java/funorb/commonui/renderer/PasswordFieldRenderer.java create mode 100644 src/main/java/funorb/commonui/renderer/TextFieldRenderer.java create mode 100644 src/main/java/funorb/commonui/renderer/TextRenderer.java create mode 100644 src/main/java/funorb/commonui/ts_.java create mode 100644 src/main/java/funorb/data/LRUCache.java create mode 100644 src/main/java/funorb/data/NodeList.java create mode 100644 src/main/java/funorb/graphics/ArgbSprite.java create mode 100644 src/main/java/funorb/graphics/Drawing.java create mode 100644 src/main/java/funorb/graphics/Font.java create mode 100644 src/main/java/funorb/graphics/NineSliceSprite.java create mode 100644 src/main/java/funorb/graphics/PalettedSpriteFont.java create mode 100644 src/main/java/funorb/graphics/PalettedSymbol.java create mode 100644 src/main/java/funorb/graphics/Point.java create mode 100644 src/main/java/funorb/graphics/Rect.java create mode 100644 src/main/java/funorb/graphics/Sprite.java create mode 100644 src/main/java/funorb/graphics/SpriteFont.java create mode 100644 src/main/java/funorb/graphics/SpriteResource.java create mode 100644 src/main/java/funorb/graphics/Symbol.java create mode 100644 src/main/java/funorb/graphics/mq_.java create mode 100644 src/main/java/funorb/graphics/vector/RasterSpan.java create mode 100644 src/main/java/funorb/graphics/vector/VectorDrawing.java create mode 100644 src/main/java/funorb/io/Buffer.java create mode 100644 src/main/java/funorb/io/ByteContainer.java create mode 100644 src/main/java/funorb/io/Bzip2.java create mode 100644 src/main/java/funorb/io/CipheredBuffer.java create mode 100644 src/main/java/funorb/io/DirectByteContainer.java create mode 100644 src/main/java/funorb/io/DuplexStream.java create mode 100644 src/main/java/funorb/io/HuffmanCoder.java create mode 100644 src/main/java/funorb/io/Inflater.java create mode 100644 src/main/java/funorb/io/Packet.java create mode 100644 src/main/java/funorb/io/PacketLengthType.java create mode 100644 src/main/java/funorb/io/ReadableBuffer.java create mode 100644 src/main/java/funorb/io/WritableBuffer.java create mode 100644 src/main/java/funorb/net/ProtocolException.java create mode 100644 src/main/java/funorb/shatteredplans/C2SPacket.java create mode 100644 src/main/java/funorb/shatteredplans/CacheFiles.java create mode 100644 src/main/java/funorb/shatteredplans/S2CPacket.java create mode 100644 src/main/java/funorb/shatteredplans/StringConstants.java create mode 100644 src/main/java/funorb/shatteredplans/client/AchievementNotification.java create mode 100644 src/main/java/funorb/shatteredplans/client/AuthMode.java create mode 100644 src/main/java/funorb/shatteredplans/client/CombatEngagementAnimationState.java create mode 100644 src/main/java/funorb/shatteredplans/client/FrameClock.java create mode 100644 src/main/java/funorb/shatteredplans/client/GameUI.java create mode 100644 src/main/java/funorb/shatteredplans/client/JagexApplet.java create mode 100644 src/main/java/funorb/shatteredplans/client/MailboxMessage.java create mode 100644 src/main/java/funorb/shatteredplans/client/Menu.java create mode 100644 src/main/java/funorb/shatteredplans/client/MessagePumpThread.java create mode 100644 src/main/java/funorb/shatteredplans/client/RenderQuality.java create mode 100644 src/main/java/funorb/shatteredplans/client/ShatteredPlansClient.java create mode 100644 src/main/java/funorb/shatteredplans/client/Sounds.java create mode 100644 src/main/java/funorb/shatteredplans/client/TutorialMessage.java create mode 100644 src/main/java/funorb/shatteredplans/client/TutorialMessageId.java create mode 100644 src/main/java/funorb/shatteredplans/client/TutorialMessages.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/AbstractGameView.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/BuildEvent.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/BuildFleetsEvent.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/ClientGameSession.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/CombatEngagementLog.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/CombatExplosion.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/CombatLogEvent.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/FleetRetreatEvent.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/GameView.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/MoveFleetsAnimationState.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/PlayerStats.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/StellarBombEvent.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/TickTimer.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/TurnEventLog.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/TutorialObjective.java create mode 100644 src/main/java/funorb/shatteredplans/client/game/TutorialState.java create mode 100644 src/main/java/funorb/shatteredplans/client/intro/IntroAnimation.java create mode 100644 src/main/java/funorb/shatteredplans/client/intro/RenderedTextLine.java create mode 100644 src/main/java/funorb/shatteredplans/client/intro/nd_.java create mode 100644 src/main/java/funorb/shatteredplans/client/intro/sb_.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/Button.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/ChatMessage.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/DiplomacyPanelState.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/FixedPanel.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/FloatingPanel.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/Icon.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/Label.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/MultilineLabel.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/PanelState.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/ProductionPanelState.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/ProjectsPanelState.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/RoundedRect.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/ScrollBar.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/ScrollBarListener.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/ScrollView.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/StatusPanelState.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/UIComponent.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/fe_.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/kb_.java create mode 100644 src/main/java/funorb/shatteredplans/client/ui/uc_.java create mode 100644 src/main/java/funorb/shatteredplans/game/BuildFleetsOrder.java create mode 100644 src/main/java/funorb/shatteredplans/game/CombinedForce.java create mode 100644 src/main/java/funorb/shatteredplans/game/ContiguousForce.java create mode 100644 src/main/java/funorb/shatteredplans/game/Force.java create mode 100644 src/main/java/funorb/shatteredplans/game/GameOptions.java create mode 100644 src/main/java/funorb/shatteredplans/game/GameSession.java create mode 100644 src/main/java/funorb/shatteredplans/game/GameState.java create mode 100644 src/main/java/funorb/shatteredplans/game/MoveFleetsOrder.java create mode 100644 src/main/java/funorb/shatteredplans/game/Player.java create mode 100644 src/main/java/funorb/shatteredplans/game/ProjectOrder.java create mode 100644 src/main/java/funorb/shatteredplans/game/TurnOrders.java create mode 100644 src/main/java/funorb/shatteredplans/game/ai/AI.java create mode 100644 src/main/java/funorb/shatteredplans/game/ai/AITask.java create mode 100644 src/main/java/funorb/shatteredplans/game/ai/CaptureTask.java create mode 100644 src/main/java/funorb/shatteredplans/game/ai/DefenseTask.java create mode 100644 src/main/java/funorb/shatteredplans/game/ai/HoldTask.java create mode 100644 src/main/java/funorb/shatteredplans/game/ai/TaskAI.java create mode 100644 src/main/java/funorb/shatteredplans/game/ai/TutorialAI1.java create mode 100644 src/main/java/funorb/shatteredplans/game/ai/TutorialAI2.java create mode 100644 src/main/java/funorb/shatteredplans/game/ai/TutorialAI3.java create mode 100644 src/main/java/funorb/shatteredplans/map/CaptureAndHoldVictoryChecker.java create mode 100644 src/main/java/funorb/shatteredplans/map/ConquestVictoryChecker.java create mode 100644 src/main/java/funorb/shatteredplans/map/DerelictsVictoryChecker.java create mode 100644 src/main/java/funorb/shatteredplans/map/Map.java create mode 100644 src/main/java/funorb/shatteredplans/map/PointsVictoryChecker.java create mode 100644 src/main/java/funorb/shatteredplans/map/StarSystem.java create mode 100644 src/main/java/funorb/shatteredplans/map/TannhauserLink.java create mode 100644 src/main/java/funorb/shatteredplans/map/TannhauserUnconnectedException.java create mode 100644 src/main/java/funorb/shatteredplans/map/TutorialVictoryChecker.java create mode 100644 src/main/java/funorb/shatteredplans/map/VictoryChecker.java create mode 100644 src/main/java/funorb/shatteredplans/map/generator/CaptureAndHoldMapGenerator.java create mode 100644 src/main/java/funorb/shatteredplans/map/generator/CaptureAndHoldMapReader.java create mode 100644 src/main/java/funorb/shatteredplans/map/generator/DerelictsMapGenerator.java create mode 100644 src/main/java/funorb/shatteredplans/map/generator/DerelictsMapReader.java create mode 100644 src/main/java/funorb/shatteredplans/map/generator/MapGenerationFailure.java create mode 100644 src/main/java/funorb/shatteredplans/map/generator/MapGenerator.java create mode 100644 src/main/java/funorb/shatteredplans/map/generator/StandardMapGenerator.java create mode 100644 src/main/java/funorb/shatteredplans/map/generator/StandardMapReader.java create mode 100644 src/main/java/funorb/shatteredplans/map/generator/TutorialMapGenerator.java create mode 100644 src/main/java/funorb/shatteredplans/map/generator/WormholeConnection.java create mode 100644 src/main/java/funorb/shatteredplans/server/ClientConnection.java create mode 100644 src/main/java/funorb/shatteredplans/server/ClientHandler.java create mode 100644 src/main/java/funorb/shatteredplans/server/ClientPlayer.java create mode 100644 src/main/java/funorb/shatteredplans/server/LobbyRoom.java create mode 100644 src/main/java/funorb/shatteredplans/server/LobbyState.java create mode 100644 src/main/java/funorb/shatteredplans/server/NetworkedGameSession.java create mode 100644 src/main/java/funorb/shatteredplans/server/ResourceStreamInput.java create mode 100644 src/main/java/funorb/shatteredplans/server/ShatteredPlansServer.java create mode 100644 src/main/java/funorb/util/ArrayUtil.java create mode 100644 src/main/java/funorb/util/BitMath.java create mode 100644 src/main/java/funorb/util/CollectionUtil.java create mode 100644 src/main/java/funorb/util/Functions.java create mode 100644 src/main/java/funorb/util/IntToBooleanFunction.java create mode 100644 src/main/java/funorb/util/IsaacCipher.java create mode 100644 src/main/java/funorb/util/IsaacRandom.java create mode 100644 src/main/java/funorb/util/MathUtil.java create mode 100644 src/main/java/funorb/util/PseudoMonotonicClock.java create mode 100644 src/main/java/funorb/util/Whirlpool.java create mode 100644 src/main/java/launcher/CommandLineOptions.java create mode 100644 src/main/java/launcher/ShatteredPlansLauncher.java create mode 100644 src/main/java/launcher/app/FOContext.java create mode 100644 src/main/java/launcher/app/FOEventQueue.java create mode 100644 src/main/java/launcher/app/FOStub.java create mode 100644 src/main/java/launcher/app/JFocusFrame.java create mode 100644 src/main/java/launcher/db/DBUtils.java create mode 100644 src/main/java/launcher/db/Database.java create mode 100644 src/main/java/launcher/db/DatabasePromise.java create mode 100644 src/main/java/launcher/db/DatabaseTask.java create mode 100644 src/main/java/launcher/options/OptionType.java create mode 100644 src/main/java/launcher/options/OptionsDatabase.java create mode 100644 src/main/java/launcher/util/HEXUtils.java create mode 100644 src/main/resources/funorb/shatteredplans/server/boot.sql create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_01_0001.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_01_000B.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_01_0015.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_02_000B.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_02_0015.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_03_0000.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_05_0000.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_05_0001.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_06_0000.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_07_0000.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_08_0000.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_09_0000.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_0A_0000.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_0B_0000.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_0C_0000.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_0D_0000.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_0D_0001.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_0E_0000.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_0E_0001.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_0E_0002.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_0E_0003.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_0E_0004.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_FF_0001.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_FF_0002.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_FF_0003.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_FF_0005.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_FF_0006.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_FF_0007.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_FF_0008.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_FF_0009.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_FF_000A.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_FF_000B.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_FF_000C.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_FF_000D.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_FF_000E.dat create mode 100644 src/main/resources/funorb/shatteredplans/server/res/res_FF_00FF.dat create mode 100644 src/main/resources/launcher/boot.sql diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c4f0460 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +*.iml +target \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d7b8e18 --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +# Shattered Plans + +Shattered Plans is a turn-based strategy game by [Jagex Ltd.][jagex] It was originally released in 2008 as part of [FunOrb][], which was sadly shut down in 2018 without any successor. This repository is a fan project that restores Shattered Plans to a playable state. Based on a decompiled archive of the original Shattered Plans client, it includes a reimplementation of the original FunOrb server, which makes Shattered Plans playable again in both singleplayer and multiplayer modes. + +[![Screenshot of Shattered Plans gameplay.][screenshot.png]][screenshot.png] + +## Running the game + +Running Shattered Plans requires [Java 17 or newer][download-java] and the latest version of the game JAR. You can then run the game by running the following command: + +```sh +java -jar shattered-plans-0.0.5.jar --local-server +``` + +As the name suggests, passing the `--local-server` flag will run a Shattered Plans server locally, allowing you to play the game in singleplayer mode. Other players can connect to your server by running + +```sh +java -jar shattered-plans-0.0.5.jar --host +``` + +replacing `` with your IP address. By default, the server runs on port 43594, but you can specify a different port using the `--port` flag. A few other options are also available, pass `--help` to see them all. + +## What works, what doesn’t, and other limitations + +All singleplayer functionality should work flawlessly. Most multiplayer functionality works as well. However, there are some bugs, unimplemented features, and other limitations: + + * When you start the game, you will be presented with a login screen. You may enter any username/password combination you like, and the server will not check it. In fact, attempting to create an account will not work: the server does not record any persistent user state. + + * Lobby and in-game chat are supported, but adding users to your friends or ignore list is not, so there is no way to send private messages. + + * Resigning is implemented, but offering a draw or a rematch is not currently supported. + + * Rated games are not implemented. + + * Achievements are not implemented. + + * There may be bugs in the server protocol, which can lead to disconnects or desyncs. Please report any bugs you come across, providing as much information as possible, and I will do my best to fix them. + +There are also some very minor improvements over the original game, but these will most likely not even be noticeable to most players. + +## Community + +If you’d like to find people to play with, or if you have any questions, [join the FunOrb discord server!][funorb-discord] This is obviously a small hobby project, so I cannot guarantee my time, but I’ll do my best to be helpful. + +[screenshot.png]: docs/screenshot.png + +[download-java]: https://www.oracle.com/java/technologies/downloads/ +[FunOrb]: https://en.wikipedia.org/wiki/FunOrb +[funorb-discord]: https://discord.gg/MGfDrDf +[jagex]: https://www.jagex.com/ diff --git a/docs/cache.md b/docs/cache.md new file mode 100644 index 0000000..93f906b --- /dev/null +++ b/docs/cache.md @@ -0,0 +1,45 @@ +# The resource cache + +All game resources are identified by an integer triple consisting of a page id, a group id, and an item id. A *page id* is an integer in the range [0, 254] that identifies a *resource page*, which is a group of broadly related resources. Shattered Plans uses the following resource pages: + +| page id | contents | +| ------: | ---------------------------------------------------------------- | +| `0x00` | common string constants | +| `0x01` | common graphics | +| `0x02` | common font data | +| `0x03` | huffman codes | +| `0x04` | Shattered Plans string constants | +| `0x05` | Shattered Plans graphics | +| `0x06` | Shattered Plans JPEG graphics | +| `0x07` | Shattered Plans font data | +| `0x08` | Shattered Plans sound effects 1 | +| `0x09` | Shattered Plans sound effects 2 | +| `0x0A` | Shattered Plans music 1 | +| `0x0B` | Shattered Plans music 2 | +| `0x0C` | Shattered Plans extra strings (tutorial messages and star names) | +| `0x0D` | Quick Chat data | +| `0x0E` | Jagex logo animation data | + +On the server, pages are stored in a set of `res_xx_yyyy.dat` files, where `xx` is a (hexadecimal) page id and `yyyy` is a group id. Many pages only have a single group, which is usually (but not always) `0000`, but some pages are split into multiple groups. + +Each page has an associated *page index*, which maps string group and item names to integer group and item ids. On disk, page indexes are stored in special `res_FF_00xx.dat` files, where `xx` is the page id. This is why there are only 254 page ids: the special `0xFF` pseudo-page id is reserved for index data. + +Finally, the special `res_FF_00FF.dat` file stores the *master index*. The master index stores a table of all the page ids known to the server, and it includes a version number for the page, along with a CRC32 and a Whirlpool hash of the page index file. + +## `MasterIndex` format + +| type | description | +| ------------------------------- | ------------------------------------------ | +| 5 bytes | unknown | +| `u8` | `pageCount` | +| `MasterIndexEntry[pageCount]` | | +| 1 byte | unknown | +| `u8[64]` | whirlpool hash of the master index entries | + +### `MasterIndexEntry` format + +| type | description | +| ------------------ | ------------------------------------------ | +| `u32` | CRC32 of the page index data | +| `u32` | page version | +| `u8[64]` | whirlpool hash of the page index data | diff --git a/docs/screenshot.png b/docs/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..2e3195f14bd0cb1ab26f05c9b0a7c2b2bac06cc9 GIT binary patch literal 397883 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�$O(C<)5 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

I@vEA^^QHq}KW@GMxcH&jlj4|c7yEI= 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

+;Us^B-TR}j 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 + + + 4.0.0 + + net.alterorb + shatteredplans + 0.0.5 + + Shattered Plans + https://alterorb.net + + + UTF-8 + 17 + 4.1.79.Final + + + + + org.jetbrains + annotations + 23.0.0 + + + org.xerial + sqlite-jdbc + 3.36.0.3 + + + io.netty + netty-transport + ${netty.version} + + + io.netty + netty-handler + ${netty.version} + + + commons-cli + commons-cli + 1.5.0 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + default-jar + + true + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.3.0 + + + package + + shade + + + + + false + + + *:* + + META-INF/**/module-info.class + META-INF/MANIFEST.MF + META-INF/**/pom.xml + META-INF/**/*.properties + + + + + + launcher.ShatteredPlansLauncher + + + + + + se.eris + notnull-instrumenter-maven-plugin + 1.1.1 + + + + instrument + tests-instrument + + + + + + org.jetbrains + annotations + 23.0.0 + + + + + + diff --git a/src/main/java/funorb/Strings.java b/src/main/java/funorb/Strings.java new file mode 100644 index 0000000..0727cb3 --- /dev/null +++ b/src/main/java/funorb/Strings.java @@ -0,0 +1,441 @@ +package funorb; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; + +import java.util.Arrays; +import java.util.Objects; + +public final class Strings { + @SuppressWarnings("WeakerAccess") + public static final char NON_BREAKING_SPACE = '\u00A0'; + public static final char EM_DASH = '\u2014'; + + /** + * Contains the characters encoded as {@code 0x80}–{@code 0x9F} under + * Windows-1252 (commonly known as “Latin-1”). These are the only characters + * in the Windows-1252 code page that are not encoded the same way in Unicode. + */ + public static final char[] WINDOWS_1252_CHARS = {'€', 0, '‚', 'ƒ', '„', '…', '†', '‡', 'ˆ', '‰', 'Š', '‹', 'Œ', 0, 'Ž', 0, 0, '‘', '’', '“', '”', '•', '–', '—', '˜', '™', 'š', '›', 'œ', 0, 'ž', 'Ÿ'}; + private static final int WINDOWS_1252_SPECIALS_START = 0x80; + private static final int WINDOWS_1252_SPECIALS_END = 0x9f; + + private static final char[] NORMALIZABLE_CHARS = {' ', NON_BREAKING_SPACE, '_', '-', 'à', 'á', 'â', 'ä', 'ã', 'À', 'Á', 'Â', 'Ä', 'Ã', 'è', 'é', 'ê', 'ë', 'È', 'É', 'Ê', 'Ë', 'í', 'î', 'ï', 'Í', 'Î', 'Ï', 'ò', 'ó', 'ô', 'ö', 'õ', 'Ò', 'Ó', 'Ô', 'Ö', 'Õ', 'ù', 'ú', 'û', 'ü', 'Ù', 'Ú', 'Û', 'Ü', 'ç', 'Ç', 'ÿ', 'Ÿ', 'ñ', 'Ñ', 'ß'}; + private static final char[] EXTRA_NORMALIZABLE_CHARS = {'[', ']', '#'}; + + private static boolean isSpecialWindows1252Byte(final int n) { + return n >= WINDOWS_1252_SPECIALS_START && n <= WINDOWS_1252_SPECIALS_END; + } + + @Contract(pure = true) + public static char decode1252Char(final byte b) { + final int n = b & 255; + if (n == 0) { + throw new IllegalArgumentException("unexpected NUL char"); + } + if (isSpecialWindows1252Byte(n)) { + final char c = WINDOWS_1252_CHARS[n - 128]; + if (c == 0) { + return '?'; + } else { + return c; + } + } + + return (char) n; + } + + @Contract(value = "_, _, _ -> new", pure = true) + public static @NotNull String decode1252String(final byte[] bytes, final int startPos, final int byteLen) { + final char[] chars = new char[byteLen]; + int strLen = 0; + for (int i = 0; i < byteLen; ++i) { + final byte encoded = bytes[i + startPos]; + if (encoded == 0) continue; // ignore NULs + chars[strLen++] = decode1252Char(encoded); + } + return new String(chars, 0, strLen); + } + + public static String decode1252String(final byte[] bytes) { + return decode1252String(bytes, 0, bytes.length); + } + + public static byte encode1252Char(final char c) { + if (c == 0) { + return '?'; + } else if (c < WINDOWS_1252_SPECIALS_START || (c > WINDOWS_1252_SPECIALS_END && c <= 0xff)) { + return (byte) c; + } else { + return switch (c) { + case 0x20ac -> 0xffffff80; + case 0x201a -> 0xffffff82; + case 0x0192 -> 0xffffff83; + case 0x201e -> 0xffffff84; + case 0x2026 -> 0xffffff85; + case 0x2020 -> 0xffffff86; + case 0x2021 -> 0xffffff87; + case 0x02c6 -> 0xffffff88; + case 0x2030 -> 0xffffff89; + case 0x0160 -> 0xffffff8a; + case 0x2039 -> 0xffffff8b; + case 0x0152 -> 0xffffff8c; + case 0x017d -> 0xffffff8e; + case 0x2018 -> 0xffffff91; + case 0x2019 -> 0xffffff92; + case 0x201c -> 0xffffff93; + case 0x201d -> 0xffffff94; + case 0x2022 -> 0xffffff95; + case 0x2013 -> 0xffffff96; + case 0x2014 -> 0xffffff97; + case 0x02dc -> 0xffffff98; + case 0x2122 -> 0xffffff99; + case 0x0161 -> 0xffffff9a; + case 0x203a -> 0xffffff9b; + case 0x0153 -> 0xffffff9c; + case 0x017e -> 0xffffff9e; + case 0x0178 -> 0xffffff9f; + default -> '?'; + }; + } + } + + public static int encode1252String(final CharSequence src, final byte[] dest, final int destOffset, final int len) { + for (int i = 0; i < len; ++i) { + final char c = src.charAt(i); + dest[destOffset + i] = encode1252Char(c); + } + return len; + } + + @Contract(value = "_ -> new", pure = true) + public static byte[] encode1252String(final CharSequence cs) { + final byte[] bs = new byte[cs.length()]; + encode1252String(cs, bs, 0, cs.length()); + return bs; + } + + public static boolean isAlphanumeric(final char c) { + return c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z'; + } + + private static char normalize(final char c) { + if (c == ' ' || c == NON_BREAKING_SPACE || c == '_' || c == '-') { + return '_'; + } else if (c == '[' || c == ']' || c == '#') { + return c; + } else if (c == 224 || c == 225 || c == 226 || c == 228 || c == 227 || c == 192 || c == 193 || c == 194 || c == 196 || c == 195) { + return 'a'; + } else if (c == 232 || c == 233 || c == 234 || c == 235 || c == 200 || c == 201 || c == 202 || c == 203) { + return 'e'; + } else if (c == 237 || c == 238 || c == 239 || c == 205 || c == 206 || c == 207) { + return 'i'; + } else if (c == 242 || c == 243 || c == 244 || c == 246 || c == 245 || c == 210 || c == 211 || c == 212 || c == 214 || c == 213) { + return 'o'; + } else if (c == 249 || c == 250 || c == 251 || c == 252 || c == 217 || c == 218 || c == 219 || c == 220) { + return 'u'; + } else if (c == 231 || c == 199) { + return 'c'; + } else if (c == 255 || c == 376) { + return 'y'; + } else if (c == 241 || c == 209) { + return 'n'; + } else if (c == 223) { + return 'b'; + } else { + return Character.toLowerCase(c); + } + } + + public static boolean isNormalizable(final char c) { + if (Character.isISOControl(c)) { + return false; + } else if (isAlphanumeric(c)) { + return true; + } else { + for (final char item : NORMALIZABLE_CHARS) { + if (c == item) { + return true; + } + } + + for (final char item : EXTRA_NORMALIZABLE_CHARS) { + if (c == item) { + return true; + } + } + + return false; + } + } + + @Contract(value = "null -> null", pure = true) + public static String normalize(final CharSequence str) { + if (str == null) { + return null; + } + + int startPos = 0; + int endPos = str.length(); + while (startPos < endPos && isSpaceLikeUsernameChar(str.charAt(startPos))) { + ++startPos; + } + while (endPos > startPos && isSpaceLikeUsernameChar(str.charAt(endPos - 1))) { + --endPos; + } + + final int len = endPos - startPos; + if (len < 1 || len > 12) { + return null; + } + + final StringBuilder sb = new StringBuilder(len); + for (int i = startPos; i < endPos; ++i) { + final char c = str.charAt(i); + if (isNormalizable(c)) { + final char normalized = normalize(c); + if (normalized != 0) { + sb.append(normalized); + } + } + } + + if (sb.isEmpty()) { + return null; + } else { + return sb.toString(); + } + } + + public static @NotNull String normalizeIfPossible(final @NotNull String str) { + return Objects.requireNonNullElse(normalize(str), str); + } + + public static boolean isSpaceLikeUsernameChar(final char c) { + return c == ' ' || c == NON_BREAKING_SPACE || c == '_' || c == '-'; + } + + public static boolean isAlpha(final char var1) { + return var1 >= 'A' && var1 <= 'Z' || var1 >= 'a' && var1 <= 'z'; + } + + public static boolean isDigit(final char c) { + return c >= '0' && c <= '9'; + } + + @Contract(pure = true) + public static String format(final String template, final String... params) { + final int var3 = template.length(); + int var4 = var3; + int var5 = 0; + + while (true) { + final int var6 = template.indexOf("<%", var5); + int var8; + if (var6 < 0) { + + final StringBuilder var11 = new StringBuilder(var4); + var5 = 0; + int var12 = 0; + + while (true) { + var8 = template.indexOf("<%", var5); + if (var8 < 0) { + var11.append(template.substring(var12)); + return var11.toString(); + } + + var5 = 2 + var8; + while (var3 > var5 && isDigit(template.charAt(var5))) { + ++var5; + } + + final String var9 = template.substring(var8 + 2, var5); + if (a783wk(var9) && var5 < var3 && template.charAt(var5) == '>') { + ++var5; + final int var10 = parseDecimalInteger(var9); + var11.append(template, var12, var8); + var11.append(params[var10]); + var12 = var5; + } + } + } + + var5 = var6 + 2; + while (var5 < var3 && isDigit(template.charAt(var5))) { + ++var5; + } + + final String var7 = template.substring(2 + var6, var5); + if (a783wk(var7) && var5 < var3 && template.charAt(var5) == '>') { + ++var5; + var8 = parseDecimalInteger(var7); + var4 += params[var8].length() - var5 + var6; + } + } + } + + public static int parseDecimalInteger(final CharSequence var0) { + return parseInteger(10, var0); + } + + @Contract(pure = true) + private static int parseInteger(@Range(from = 2, to = 36) final int base, final CharSequence var1) { + boolean var3 = false; + boolean var5 = false; + int var6 = 0; + final int var7 = var1.length(); + + for (int var8 = 0; var7 > var8; ++var8) { + final char var9 = var1.charAt(var8); + if (var8 == 0) { + if (var9 == '-') { + var3 = true; + continue; + } + + if (var9 == '+') { + continue; + } + } + + int var11; + if (var9 >= '0' && var9 <= '9') { + var11 = var9 - 48; + } else if (var9 >= 'A' && var9 <= 'Z') { + var11 = var9 - 55; + } else { + if (var9 < 'a' || var9 > 'z') { + throw new NumberFormatException(); + } + + var11 = var9 - 87; + } + + if (var11 >= base) { + throw new NumberFormatException(); + } + + if (var3) { + var11 = -var11; + } + + final int var10 = var6 * base + var11; + if (var10 / base != var6) { + throw new NumberFormatException(); + } + + var5 = true; + var6 = var10; + } + + if (var5) { + return var6; + } else { + throw new NumberFormatException(); + } + } + + @Contract(pure = true) + public static boolean a783wk(final CharSequence var1) { + boolean var4 = false; + boolean var5 = false; + int var6 = 0; + final int var7 = var1.length(); + + for (int var9 = 0; var9 < var7; ++var9) { + final char var10 = var1.charAt(var9); + if (var9 == 0) { + if (var10 == '-') { + var4 = true; + continue; + } + + if (var10 == '+') { + continue; + } + } + + int var12; + if (var10 >= '0' && var10 <= '9') { + var12 = var10 - 48; + } else if (var10 >= 'A' && var10 <= 'Z') { + var12 = var10 - 55; + } else { + if (var10 < 'a' || var10 > 'z') { + return false; + } + + var12 = var10 - 87; + } + + if (var12 >= 10) { + return false; + } + + if (var4) { + var12 = -var12; + } + + final int var11 = var6 * 10 + var12; + if (var11 / 10 != var6) { + return false; + } + + var6 = var11; + var5 = true; + } + + return var5; + } + + public static int parseHexInteger(final CharSequence var0) { + return parseInteger(16, var0); + } + + public static String formatNamed(final String template, final String paramName, final String paramValue) { + int var5 = template.length(); + int var6 = 0; + final String var7 = "<%" + paramName + ">"; + + while (true) { + final int var8 = template.indexOf(var7, var6); + if (var8 < 0) { + var6 = 0; + final StringBuilder var10 = new StringBuilder(var5); + + while (true) { + final int var9 = template.indexOf(var7, var6); + if (var9 < 0) { + var10.append(template, var6, template.length()); + return var10.toString(); + } + + var10.append(template, var6, var9); + var10.append(paramValue); + var6 = var7.length() + var9; + } + } + + var6 = var8 + var7.length(); + var5 += paramValue.length() - var7.length(); + } + } + + public static String[] splitLines(final String str) { + final String[] lines = str.split("\n"); + Arrays.setAll(lines, var4 -> lines[var4].trim()); + return lines; + } + + public static int lastIndexOf(final String str, final String sub) { + int nextIndex = str.indexOf(sub); + int prevIndex = nextIndex; + while (nextIndex != -1) { + prevIndex = nextIndex; + nextIndex = str.indexOf(sub, 1 + nextIndex); + } + return prevIndex; + } +} diff --git a/src/main/java/funorb/audio/AudioThread.java b/src/main/java/funorb/audio/AudioThread.java new file mode 100644 index 0000000..a263144 --- /dev/null +++ b/src/main/java/funorb/audio/AudioThread.java @@ -0,0 +1,38 @@ +package funorb.audio; + +import funorb.client.JagexBaseApplet; +import funorb.shatteredplans.client.MessagePumpThread; + +public final class AudioThread implements Runnable { + public static final int NUM_CHANNELS = 2; + public static AudioThread instance; + + public final SampledAudioChannel[] channels = new SampledAudioChannel[NUM_CHANNELS]; + private final MessagePumpThread messagePumpThread; + public volatile boolean shutdownRequested = false; + public volatile boolean isRunning = false; + + public AudioThread(final MessagePumpThread messagePumpThread) { + this.messagePumpThread = messagePumpThread; + } + + @Override + public void run() { + this.isRunning = true; + try { + while (!this.shutdownRequested) { + for (int i = 0; i < NUM_CHANNELS; ++i) { + final SampledAudioChannel channel = this.channels[i]; + if (channel != null) { + channel.doSomethingThatSeemsRelatedToAudio(); + } + } + + JagexBaseApplet.maybeSleep(10L); + this.messagePumpThread.postEvent(null); + } + } finally { + this.isRunning = false; + } + } +} diff --git a/src/main/java/funorb/audio/MusicTrack.java b/src/main/java/funorb/audio/MusicTrack.java new file mode 100644 index 0000000..bf09cb8 --- /dev/null +++ b/src/main/java/funorb/audio/MusicTrack.java @@ -0,0 +1,408 @@ +package funorb.audio; + +import funorb.cache.ResourceLoader; +import funorb.io.Buffer; + +import java.util.HashMap; +import java.util.Map; + +public final class MusicTrack { + public byte[] _h; + public Map _i; + + private MusicTrack(final Buffer var1) { + var1.pos = var1.data.length - 3; + final int var2 = var1.readUByte(); + final int var3 = var1.readUShort(); + int var4 = 14 + var2 * 10; + var1.pos = 0; + int var5 = 0; + int var6 = 0; + int var7 = 0; + int var8 = 0; + int var9 = 0; + int var10 = 0; + int var11 = 0; + int var12 = 0; + + int var13; + int var14; + int var15; + for (var13 = 0; var13 < var2; ++var13) { + var14 = -1; + + while (true) { + var15 = var1.readUByte(); + if (var15 != var14) { + ++var4; + } + + var14 = var15 & 15; + if (var15 == 7) { + break; + } + + if (var15 == 23) { + ++var5; + } else if (var14 == 0) { + ++var7; + } else if (var14 == 1) { + ++var8; + } else if (var14 == 2) { + ++var6; + } else if (var14 == 3) { + ++var9; + } else if (var14 == 4) { + ++var10; + } else if (var14 == 5) { + ++var11; + } else { + if (var14 != 6) { + throw new RuntimeException(); + } + + ++var12; + } + } + } + + var4 += 5 * var5; + var4 += 2 * (var7 + var8 + var6 + var9 + var11); + var4 += var10 + var12; + var13 = var1.pos; + var14 = var2 + var5 + var6 + var7 + var8 + var9 + var10 + var11 + var12; + + for (var15 = 0; var15 < var14; ++var15) { + var1.readVariableInt(); + } + + var4 += var1.pos - var13; + var15 = var1.pos; + int var16 = 0; + int var17 = 0; + int var18 = 0; + int var19 = 0; + int var20 = 0; + int var21 = 0; + int var22 = 0; + int var23 = 0; + int var24 = 0; + int var25 = 0; + int var26 = 0; + int var27 = 0; + int var28 = 0; + + int var29; + for (var29 = 0; var29 < var6; ++var29) { + var28 = var28 + var1.readUByte() & 127; + if (var28 == 0 || var28 == 32) { + ++var12; + } else if (var28 == 1) { + ++var16; + } else if (var28 == 33) { + ++var17; + } else if (var28 == 7) { + ++var18; + } else if (var28 == 39) { + ++var19; + } else if (var28 == 10) { + ++var20; + } else if (var28 == 42) { + ++var21; + } else if (var28 == 99) { + ++var22; + } else if (var28 == 98) { + ++var23; + } else if (var28 == 101) { + ++var24; + } else if (var28 == 100) { + ++var25; + } else if (var28 == 64 || var28 == 65 || var28 == 120 || var28 == 121 || var28 == 123) { + ++var26; + } else { + ++var27; + } + } + + var29 = 0; + int var30 = var1.pos; + var1.pos += var26; + int var31 = var1.pos; + var1.pos += var11; + int var32 = var1.pos; + var1.pos += var10; + int var33 = var1.pos; + var1.pos += var9; + int var34 = var1.pos; + var1.pos += var16; + int var35 = var1.pos; + var1.pos += var18; + int var36 = var1.pos; + var1.pos += var20; + int var37 = var1.pos; + var1.pos += var7 + var8 + var11; + int var38 = var1.pos; + var1.pos += var7; + int var39 = var1.pos; + var1.pos += var27; + int var40 = var1.pos; + var1.pos += var8; + int var41 = var1.pos; + var1.pos += var17; + int var42 = var1.pos; + var1.pos += var19; + int var43 = var1.pos; + var1.pos += var21; + int var44 = var1.pos; + var1.pos += var12; + int var45 = var1.pos; + var1.pos += var9; + int var46 = var1.pos; + var1.pos += var22; + int var47 = var1.pos; + var1.pos += var23; + int var48 = var1.pos; + var1.pos += var24; + int var49 = var1.pos; + var1.pos += var25; + int var50 = var1.pos; + var1.pos += var5 * 3; + this._h = new byte[var4]; + final Buffer var51 = new Buffer(this._h); + var51.writeInt(1297377380); + var51.writeInt(6); + var51.writeShort(var2 > 1 ? 1 : 0); + var51.writeShort(var2); + var51.writeShort(var3); + var1.pos = var13; + int var52 = 0; + int var53 = 0; + int var54 = 0; + int var55 = 0; + int var56 = 0; + int var57 = 0; + int var58 = 0; + final int[] var59 = new int[128]; + int i = 0; + + label221: + for (int var60 = 0; var60 < var2; ++var60) { + var51.writeInt(1297379947); + var51.pos += 4; + final int var61 = var51.pos; + int var62 = -1; + + while (true) { + while (true) { + final int var63 = var1.readVariableInt(); + var51.a556(var63); + final int var64 = var1.data[var29++] & 255; + final boolean var65 = var64 != var62; + var62 = var64 & 15; + if (var64 == 7) { + if (var65) { + var51.writeByte(255); + } + + var51.writeByte(47); + var51.writeByte(0); + var51.c093(var51.pos - var61); + continue label221; + } + + if (var64 == 23) { + if (var65) { + var51.writeByte(255); + } + + var51.writeByte(81); + var51.writeByte(3); + var51.writeByte(var1.data[var50++]); + var51.writeByte(var1.data[var50++]); + var51.writeByte(var1.data[var50++]); + } else { + var52 ^= var64 >> 4; + if (var62 == 0) { + if (var65) { + var51.writeByte(144 + var52); + } + + var53 += var1.data[var37++]; + var54 += var1.data[var38++]; + var51.writeByte(var53 & 127); + var51.writeByte(var54 & 127); + } else if (var62 == 1) { + if (var65) { + var51.writeByte(128 + var52); + } + + var53 += var1.data[var37++]; + var55 += var1.data[var40++]; + var51.writeByte(var53 & 127); + var51.writeByte(var55 & 127); + } else if (var62 == 2) { + if (var65) { + var51.writeByte(176 + var52); + } + + i = i + var1.data[var15++] & 127; + var51.writeByte(i); + final byte var66; + if (i == 0 || i == 32) { + var66 = var1.data[var44++]; + } else if (i == 1) { + var66 = var1.data[var34++]; + } else if (i == 33) { + var66 = var1.data[var41++]; + } else if (i == 7) { + var66 = var1.data[var35++]; + } else if (i == 39) { + var66 = var1.data[var42++]; + } else if (i == 10) { + var66 = var1.data[var36++]; + } else if (i == 42) { + var66 = var1.data[var43++]; + } else if (i == 99) { + var66 = var1.data[var46++]; + } else if (i == 98) { + var66 = var1.data[var47++]; + } else if (i == 101) { + var66 = var1.data[var48++]; + } else if (i == 100) { + var66 = var1.data[var49++]; + } else if (i == 64 || i == 65 || i == 120 || i == 121 || i == 123) { + var66 = var1.data[var30++]; + } else { + var66 = var1.data[var39++]; + } + + final int var67 = var66 + var59[i]; + var59[i] = var67; + var51.writeByte(var67 & 127); + } else if (var62 == 3) { + if (var65) { + var51.writeByte(224 + var52); + } + + var56 += var1.data[var45++]; + var56 += var1.data[var33++] << 7; + var51.writeByte(var56 & 127); + var51.writeByte(var56 >> 7 & 127); + } else if (var62 == 4) { + if (var65) { + var51.writeByte(208 + var52); + } + + var57 += var1.data[var32++]; + var51.writeByte(var57 & 127); + } else if (var62 == 5) { + if (var65) { + var51.writeByte(160 + var52); + } + + var53 += var1.data[var37++]; + var58 += var1.data[var31++]; + var51.writeByte(var53 & 127); + var51.writeByte(var58 & 127); + } else { + if (var62 != 6) { + throw new RuntimeException(); + } + + if (var65) { + var51.writeByte(192 + var52); + } + + var51.writeByte(var1.data[var44++]); + } + } + } + } + } + + } + + public static MusicTrack load(final ResourceLoader loader, final String item) { + final byte[] data = loader.getResource("", item); + return data == null ? null : new MusicTrack(new Buffer(data)); + } + + public void a797() { + if (this._i == null) { + this._i = new HashMap<>(); + final int[] var1 = new int[16]; + final int[] var2 = new int[16]; + var2[9] = 128; + var1[9] = 128; + final pi_ var4 = new pi_(this._h); + final int var5 = var4.c784(); + + int var6; + for (var6 = 0; var6 < var5; ++var6) { + var4.b150(var6); + var4.d150(var6); + var4.e150(var6); + } + + label53: + do { + while (true) { + var6 = var4.g784(); + final int var7 = var4._b[var6]; + + while (var4._b[var6] == var7) { + var4.b150(var6); + final int var8 = var4.a137(var6); + if (var8 == 1) { + var4.e797(); + var4.e150(var6); + continue label53; + } + + final int var9 = var8 & 240; + int var10; + int var11; + int var12; + if (var9 == 176) { + var10 = var8 & 15; + var11 = var8 >> 8 & 127; + var12 = var8 >> 16 & 127; + if (var11 == 0) { + var1[var10] = (var1[var10] & -2080769) + (var12 << 14); + } + + if (var11 == 32) { + var1[var10] = (var1[var10] & -16257) + (var12 << 7); + } + } + + if (var9 == 192) { + var10 = var8 & 15; + var11 = var8 >> 8 & 127; + var2[var10] = var1[var10] + var11; + } + + if (var9 == 144) { + var10 = var8 & 15; + var11 = var8 >> 8 & 127; + var12 = var8 >> 16 & 127; + if (var12 > 0) { + final int var13 = var2[var10]; + final byte[] var14 = this._i.computeIfAbsent(var13, k -> new byte[128]); + var14[var11] = 1; + } + } + + var4.d150(var6); + var4.e150(var6); + } + } + } while (!var4.a801()); + + } + } + + public void b797() { + this._i = null; + } +} diff --git a/src/main/java/funorb/audio/PlayingSound.java b/src/main/java/funorb/audio/PlayingSound.java new file mode 100644 index 0000000..f6a7fe7 --- /dev/null +++ b/src/main/java/funorb/audio/PlayingSound.java @@ -0,0 +1,19 @@ +package funorb.audio; + +import funorb.shatteredplans.client.Sounds; + +public final class PlayingSound { + public final al_ _p; + public int volume; + + public PlayingSound(final al_ var1) { + this._p = var1; + this.volume = var1.getVolume(); + this._p.setVolume((128 + (this.volume * Sounds.soundVolume)) >> 8); + } + + public void setVolume(final int volume) { + this.volume = volume; + this._p.setVolume((128 + (volume * Sounds.soundVolume)) >> 8); + } +} diff --git a/src/main/java/funorb/audio/SampledAudioChannel.java b/src/main/java/funorb/audio/SampledAudioChannel.java new file mode 100644 index 0000000..34af135 --- /dev/null +++ b/src/main/java/funorb/audio/SampledAudioChannel.java @@ -0,0 +1,345 @@ +package funorb.audio; + +import funorb.client.JagexBaseApplet; +import funorb.util.BitMath; +import funorb.util.PseudoMonotonicClock; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine.Info; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.SourceDataLine; +import java.io.Closeable; +import java.util.Arrays; + +public final class SampledAudioChannel implements Closeable { + public static final int SAMPLES_PER_SECOND = 22050; + private static final int BYTES_PER_CHANNEL_PER_WRITE = 512; + + private final AudioFormat format = new AudioFormat(SAMPLES_PER_SECOND, 16, 2, true, false); + private final byte[] buffer = new byte[1024]; + private final tn_[] _o = new tn_[8]; + private final tn_[] _s = new tn_[8]; + public int[] data; + public int _g; + public int _b; + private SourceDataLine line; + private int lineBufferSizeInInts; + private boolean isShutdown = false; + private long _m = PseudoMonotonicClock.currentTimeMillis(); + private tn_ source; + private int _r = 0; + private int _l = 0; + private boolean _n = true; + private int _e = 0; + private int _a = 0; + private long _p = 0L; + private int _u; + private long _q = 0L; + + private static int a080lc(final int var1) { + final int var2 = (var1 & 0x55555555) + ((var1 >>> 1) & 0xd5555555); + final int var3 = (var2 & 0x33333333) + ((var2 & 0xcccccccc) >>> 2); + final int var4 = (var3 + (var3 >>> 4)) & 0xf0f0f0f; + final int var5 = var4 + (var4 >>> 8); + final int var6 = var5 + (var5 >>> 16); + return var6 & 255; + } + + private static void b446(final tn_ var0) { + var0._j = false; + if (var0._k != null) { + var0._k._h = 0; + } + var0.forEach(SampledAudioChannel::b446); + } + + @Override + public void close() { + if (this.line != null) { + this.line.close(); + this.line = null; + } + } + + private int bufferedInts() { + return this.lineBufferSizeInInts - (this.line.available() / 4); + } + + private void performWrite() { + for (int i = 0; i < BYTES_PER_CHANNEL_PER_WRITE; ++i) { + int var3 = this.data[i]; + if (((var3 + 0x80_00_00) & 0xff_00_00_00) != 0) { + var3 = 0x7fffff ^ (var3 >> 31); + } + this.buffer[i * 2] = (byte) (var3 >> 8); + this.buffer[i * 2 + 1] = (byte) (var3 >> 16); + } + + this.line.write(this.buffer, 0, BYTES_PER_CHANNEL_PER_WRITE * 2); + } + + public void open(final int size) throws LineUnavailableException { + try { + final Info var2 = new Info(SourceDataLine.class, this.format, size * 4); + this.line = (SourceDataLine) AudioSystem.getLine(var2); + this.line.open(); + this.line.start(); + this.lineBufferSizeInInts = size; + } catch (final LineUnavailableException var3) { + if (a080lc(size) == 1) { + this.line = null; + throw var3; + } else { + this.open(BitMath.nextLowestPowerOf2(size)); + } + } + } + + private void a704(final int[] data) { + Arrays.fill(data, 0, BYTES_PER_CHANNEL_PER_WRITE, 0); + this._a -= 256; + if (this.source != null && this._a <= 0) { + this._a += 1378; + b446(this.source); + this.a607(this.source, this.source.c784()); + int var4 = 0; + int var5 = 255; + + tn_ var10; + label106: + for (int var6 = 7; var5 != 0; --var6) { + int var7; + int var8; + if (var6 < 0) { + var7 = var6 & 3; + var8 = -(var6 >> 2); + } else { + var7 = var6; + var8 = 0; + } + + for (int var9 = (var5 >>> var7) & 0x11111111; var9 != 0; var9 >>>= 4) { + if ((var9 & 1) != 0) { + var5 &= ~(1 << var7); + var10 = null; + tn_ var11 = this._o[var7]; + + label100: + while (true) { + while (true) { + if (var11 == null) { + break label100; + } + + final kk_ var12 = var11._k; + if (var12 != null && var12._h > var8) { + var5 |= 1 << var7; + var10 = var11; + var11 = var11._h; + } else { + var11._j = true; + final int var13 = var11.a784(); + var4 += var13; + if (var12 != null) { + var12._h += var13; + } + + if (var4 >= 32) { + break label106; + } + + final int var15 = var11._i; + var11.forEach(var14 -> this.a607(var14, var15 * var14.c784() >> 8)); + + final tn_ var18 = var11._h; + var11._h = null; + if (var10 == null) { + this._o[var7] = var18; + } else { + var10._h = var18; + } + + if (var18 == null) { + this._s[var7] = var10; + } + + var11 = var18; + } + } + } + } + + var7 += 4; + ++var8; + } + } + + for (int var6 = 0; var6 < 8; ++var6) { + tn_ var16 = this._o[var6]; + this._s[var6] = null; + + for (this._o[var6] = null; var16 != null; var16 = var10) { + var10 = var16._h; + var16._h = null; + } + } + } + + if (this._a < 0) { + this._a = 0; + } + + if (this.source != null) { + this.source.b397(data, 0, 256); + } + + this._m = PseudoMonotonicClock.currentTimeMillis(); + } + + private void b150() { + this._a -= 256; + if (this._a < 0) { + this._a = 0; + } + if (this.source != null) { + this.source.a150(256); + } + } + + private void a607(final tn_ var1, final int var2) { + final int i = var2 >> 5; + final tn_ var4 = this._s[i]; + if (var4 == null) { + this._o[i] = var1; + } else { + var4._h = var1; + } + + this._s[i] = var1; + var1._i = var2; + } + + public synchronized void doSomethingThatSeemsRelatedToAudio() { + if (!this.isShutdown) { + long var1 = PseudoMonotonicClock.currentTimeMillis(); + + try { + if (var1 > this._m + 6000L) { + this._m = var1 - 6000L; + } + + while (var1 > this._m + 5000L) { + this.b150(); + this._m += 256000 / SAMPLES_PER_SECOND; + var1 = PseudoMonotonicClock.currentTimeMillis(); + } + } catch (final Exception var6) { + this._m = var1; + } + + if (this.data != null) { + try { + if (this._p != 0L) { + if (var1 < this._p) { + return; + } + + this.open(this._g); + this._p = 0L; + this._n = true; + } + + int var3 = this.bufferedInts(); + if (this._r - var3 > this._l) { + this._l = this._r - var3; + } + + int var4 = this._b + this._u; + if (var4 + 0x100 > 0x4000) { + var4 = 0x3f00; + } + + if (var4 + 0x100 > this._g) { + this._g += 0x400; + if (this._g > 0x4000) { + this._g = 0x4000; + } + + this.close(); + this.open(this._g); + var3 = 0; + this._n = true; + if (var4 + 256 > this._g) { + var4 = this._g - 256; + this._u = var4 - this._b; + } + } + + while (var3 < var4) { + this.a704(this.data); + this.performWrite(); + var3 += 256; + } + + if (var1 > this._q) { + if (this._n) { + this._n = false; + } else { + if (this._l == 0 && this._e == 0) { + this.close(); + this._p = var1 + 2000L; + return; + } + + this._u = Math.min(this._e, this._l); + this._e = this._l; + } + + this._l = 0; + this._q = var1 + 2000L; + } + + this._r = var3; + } catch (final Exception var5) { + this.close(); + this._p = var1 + 2000L; + } + } + } + } + + public synchronized void setSource(final tn_ source) { + this.source = source; + } + + public synchronized void shutdown() { + if (AudioThread.instance != null) { + boolean allChannelsShutdown = true; + + for (int i = 0; i < AudioThread.NUM_CHANNELS; ++i) { + if (AudioThread.instance.channels[i] == this) { + AudioThread.instance.channels[i] = null; + } + + if (AudioThread.instance.channels[i] != null) { + allChannelsShutdown = false; + } + } + + if (allChannelsShutdown) { + AudioThread.instance.shutdownRequested = true; + + while (AudioThread.instance.isRunning) { + JagexBaseApplet.maybeSleep(50L); + } + + AudioThread.instance = null; + } + } + + this.close(); + this.data = null; + this.isShutdown = true; + } +} diff --git a/src/main/java/funorb/audio/SoundEffect.java b/src/main/java/funorb/audio/SoundEffect.java new file mode 100644 index 0000000..30e18ae --- /dev/null +++ b/src/main/java/funorb/audio/SoundEffect.java @@ -0,0 +1,21 @@ +package funorb.audio; + +public final class SoundEffect { + public final int volume; + public final kk_ _f; + + private SoundEffect(final kk_ var1, final int var2) { + this.volume = var2; + this._f = var1; + } + + @SuppressWarnings("SameParameterValue") + public static SoundEffect load1(final String item, final int var1) { + return new SoundEffect(SoundLoader.globalLoader.load1(item), var1); + } + + @SuppressWarnings("SameParameterValue") + public static SoundEffect load2(final String item, final int var1) { + return new SoundEffect(SoundLoader.globalLoader.load2(item), var1); + } +} diff --git a/src/main/java/funorb/audio/SoundLoader.java b/src/main/java/funorb/audio/SoundLoader.java new file mode 100644 index 0000000..beba589 --- /dev/null +++ b/src/main/java/funorb/audio/SoundLoader.java @@ -0,0 +1,99 @@ +package funorb.audio; + +import funorb.cache.ResourceLoader; + +import java.util.HashMap; +import java.util.Map; + +public final class SoundLoader { + public static SoundLoader globalLoader; + private final Map _a = new HashMap<>(); + private final Map _d = new HashMap<>(); + private final ResourceLoader loader1; + private final ResourceLoader loader2; + + public SoundLoader(final ResourceLoader loader1, final ResourceLoader loader2) { + this.loader1 = loader1; + this.loader2 = loader2; + } + + private kk_ load1(final int groupId, final int itemId) { + final int var5 = (itemId ^ (((groupId << 4) & 0xfff3) | (groupId >>> 12))) | (groupId << 16); + final kk_ var8 = this._d.get((long) var5); + if (var8 == null) { + final dq_ var9 = dq_.load(this.loader1, groupId, itemId); + if (var9 == null) { + return null; + } else { + final kk_ kk_ = var9.b720(); + this._d.put((long) var5, kk_); + return kk_; + } + } else { + return var8; + } + } + + public kk_ loadSingleton2(final int var3) { + if (this.loader2.groupCount() == 1) { + return this.load2(0, var3); + } else if (this.loader2.itemCount(var3) == 1) { + return this.load2(var3, 0); + } else { + throw new RuntimeException(); + } + } + + public kk_ loadSingleton1(final int var1) { + if (this.loader1.groupCount() == 1) { + return this.load1(0, var1); + } else if (this.loader1.itemCount(var1) == 1) { + return this.load1(var1, 0); + } else { + throw new RuntimeException(); + } + } + + private kk_ load2(final int var3, final int var2) { + final int var5 = (((var3 >>> 12) | (0xfff0 & (var3 << 4))) ^ var2) | (var3 << 16); + final long var6 = 0x100000000L ^ (long) var5; + kk_ var8 = this._d.get(var6); + if (var8 == null) { + fd_ var9 = this._a.get(var6); + if (var9 == null) { + var9 = fd_.a740(this.loader2, var3, var2); + if (var9 == null) { + return null; + } + + this._a.put(var6, var9); + } + + var8 = var9.a582(); + this._a.remove(var6); + this._d.put(var6, var8); + } + return var8; + } + + @SuppressWarnings("SameParameterValue") + public kk_ load2(final String item) { + final int groupId = this.loader2.lookupGroup(""); + if (groupId < 0) { + return null; + } else { + final int itemId = this.loader2.lookupItem(groupId, item); + return itemId < 0 ? null : this.load2(groupId, itemId); + } + } + + public kk_ load1(final String item) { + final int groupId = this.loader1.lookupGroup(""); + if (groupId >= 0) { + final int itemId = this.loader1.lookupItem(groupId, item); + return itemId >= 0 ? this.load1(groupId, itemId) : null; + } else { + return null; + } + } +} diff --git a/src/main/java/funorb/audio/al_.java b/src/main/java/funorb/audio/al_.java new file mode 100644 index 0000000..8f25c93 --- /dev/null +++ b/src/main/java/funorb/audio/al_.java @@ -0,0 +1,1110 @@ +package funorb.audio; + +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.Iterator; + +public final class al_ extends tn_ { + private final int _u; + private final boolean _o; + private final int _r; + private int _y; + private int _z; + private int _s; + private int _n; + private int _x; + private int _t; + private int volume; + private int _v; + private int _q; + private int _l; + private int _p; + private int _m; + + private al_(final kk_ var1, final int var2, final int volume, final int var4) { + this._k = var1; + this._u = var1._l; + this._r = var1._k; + this._o = var1._i; + this._l = var2; + this.volume = volume; + this._z = var4; + this._t = 0; + this.k797(); + } + + private static int c984(final byte[] var2, final int[] var3, int var4, int var5, final int var6, final int var7, final int var9, final int var10, final al_ var11, final int var12, final int var13) { + int var8; + if (var12 == 0 || (var8 = var5 + (var10 + 256 - var4 + var12) / var12) > var9) { + var8 = var9; + } + + var5 <<= 1; + + int var10001; + int var0; + int var1; + for (var8 <<= 1; var5 < var8; var4 += var12) { + var1 = var4 >> 8; + final byte var14 = var2[var1 - 1]; + var0 = (var14 << 8) + (var2[var1] - var14) * (var4 & 255); + var10001 = var5++; + var3[var10001] += var0 * var6 >> 6; + var10001 = var5++; + var3[var10001] += var0 * var7 >> 6; + } + + if (var12 == 0 || (var8 = (var5 >> 1) + (var10 - var4 + var12) / var12) > var9) { + var8 = var9; + } + + var8 <<= 1; + + for (var1 = var13; var5 < var8; var4 += var12) { + var0 = (var1 << 8) + (var2[var4 >> 8] - var1) * (var4 & 255); + var10001 = var5++; + var3[var10001] += var0 * var6 >> 6; + var10001 = var5++; + var3[var10001] += var0 * var7 >> 6; + } + + var11._t = var4; + return var5 >> 1; + } + + public static al_ a771(final kk_ var0, final int var1, final int var2, final int var3) { + return (var0.data == null || var0.data.length == 0) ? null : new al_(var0, var1, var2, var3); + } + + private static int b775(final byte[] var1, final int[] var2, int var3, int var4, int var5, int var6, final int var8, int var9, final al_ var10) { + var3 >>= 8; + var9 >>= 8; + var5 <<= 2; + var6 <<= 2; + int var7; + if ((var7 = var4 + var9 - var3) > var8) { + var7 = var8; + } + + var4 <<= 1; + var7 <<= 1; + + int var10001; + byte var11; + for (var7 -= 6; var4 < var7; var2[var10001] += var11 * var6) { + var11 = var1[var3++]; + var10001 = var4++; + var2[var10001] += var11 * var5; + var10001 = var4++; + var2[var10001] += var11 * var6; + var11 = var1[var3++]; + var10001 = var4++; + var2[var10001] += var11 * var5; + var10001 = var4++; + var2[var10001] += var11 * var6; + var11 = var1[var3++]; + var10001 = var4++; + var2[var10001] += var11 * var5; + var10001 = var4++; + var2[var10001] += var11 * var6; + var11 = var1[var3++]; + var10001 = var4++; + var2[var10001] += var11 * var5; + var10001 = var4++; + } + + for (var7 += 6; var4 < var7; var2[var10001] += var11 * var6) { + var11 = var1[var3++]; + var10001 = var4++; + var2[var10001] += var11 * var5; + var10001 = var4++; + } + + var10._t = var3 << 8; + return var4 >> 1; + } + + private static int b961(final byte[] var1, final int[] var2, int var3, int var4, int var5, int var6, int var7, int var8, final int var10, int var11, final al_ var12) { + var3 >>= 8; + var11 >>= 8; + var5 <<= 2; + var6 <<= 2; + var7 <<= 2; + var8 <<= 2; + int var9; + if ((var9 = var4 + var3 - (var11 - 1)) > var10) { + var9 = var10; + } + + var12._s += var12._p * (var9 - var4); + var4 <<= 1; + var9 <<= 1; + + byte var13; + int var10001; + for (var9 -= 6; var4 < var9; var6 += var8) { + var13 = var1[var3--]; + var10001 = var4++; + var2[var10001] += var13 * var5; + var5 += var7; + var10001 = var4++; + var2[var10001] += var13 * var6; + var6 += var8; + var13 = var1[var3--]; + var10001 = var4++; + var2[var10001] += var13 * var5; + var5 += var7; + var10001 = var4++; + var2[var10001] += var13 * var6; + var6 += var8; + var13 = var1[var3--]; + var10001 = var4++; + var2[var10001] += var13 * var5; + var5 += var7; + var10001 = var4++; + var2[var10001] += var13 * var6; + var6 += var8; + var13 = var1[var3--]; + var10001 = var4++; + var2[var10001] += var13 * var5; + var5 += var7; + var10001 = var4++; + var2[var10001] += var13 * var6; + } + + for (var9 += 6; var4 < var9; var6 += var8) { + var13 = var1[var3--]; + var10001 = var4++; + var2[var10001] += var13 * var5; + var5 += var7; + var10001 = var4++; + var2[var10001] += var13 * var6; + } + + var12._y = var5 >> 2; + var12._m = var6 >> 2; + var12._t = var3 << 8; + return var4 >> 1; + } + + private static int a961(final byte[] var1, final int[] var2, int var3, int var4, int var5, int var6, int var7, int var8, final int var10, int var11, final al_ var12) { + var3 >>= 8; + var11 >>= 8; + var5 <<= 2; + var6 <<= 2; + var7 <<= 2; + var8 <<= 2; + int var9; + if ((var9 = var4 + var11 - var3) > var10) { + var9 = var10; + } + + var12._s += var12._p * (var9 - var4); + var4 <<= 1; + var9 <<= 1; + + byte var13; + int var10001; + for (var9 -= 6; var4 < var9; var6 += var8) { + var13 = var1[var3++]; + var10001 = var4++; + var2[var10001] += var13 * var5; + var5 += var7; + var10001 = var4++; + var2[var10001] += var13 * var6; + var6 += var8; + var13 = var1[var3++]; + var10001 = var4++; + var2[var10001] += var13 * var5; + var5 += var7; + var10001 = var4++; + var2[var10001] += var13 * var6; + var6 += var8; + var13 = var1[var3++]; + var10001 = var4++; + var2[var10001] += var13 * var5; + var5 += var7; + var10001 = var4++; + var2[var10001] += var13 * var6; + var6 += var8; + var13 = var1[var3++]; + var10001 = var4++; + var2[var10001] += var13 * var5; + var5 += var7; + var10001 = var4++; + var2[var10001] += var13 * var6; + } + + for (var9 += 6; var4 < var9; var6 += var8) { + var13 = var1[var3++]; + var10001 = var4++; + var2[var10001] += var13 * var5; + var5 += var7; + var10001 = var4++; + var2[var10001] += var13 * var6; + } + + var12._y = var5 >> 2; + var12._m = var6 >> 2; + var12._t = var3 << 8; + return var4 >> 1; + } + + private static int d984(final byte[] var2, final int[] var3, int var4, int var5, final int var6, final int var7, final int var9, final int var10, final al_ var11, final int var12, final int var13) { + int var8; + if (var12 == 0 || (var8 = var5 + (var10 - var4 + var12 - 257) / var12) > var9) { + var8 = var9; + } + + var5 <<= 1; + + byte var14; + int var10001; + int var0; + int var1; + for (var8 <<= 1; var5 < var8; var4 += var12) { + var1 = var4 >> 8; + var14 = var2[var1]; + var0 = (var14 << 8) + (var2[var1 + 1] - var14) * (var4 & 255); + var10001 = var5++; + var3[var10001] += var0 * var6 >> 6; + var10001 = var5++; + var3[var10001] += var0 * var7 >> 6; + } + + if (var12 == 0 || (var8 = (var5 >> 1) + (var10 - var4 + var12 - 1) / var12) > var9) { + var8 = var9; + } + + var8 <<= 1; + + for (var1 = var13; var5 < var8; var4 += var12) { + var14 = var2[var4 >> 8]; + var0 = (var14 << 8) + (var1 - var14) * (var4 & 255); + var10001 = var5++; + var3[var10001] += var0 * var6 >> 6; + var10001 = var5++; + var3[var10001] += var0 * var7 >> 6; + } + + var11._t = var4; + return var5 >> 1; + } + + public static al_ a638(final kk_ var0, final int volume) { + if (var0.data == null || var0.data.length == 0) { + return null; + } else { + return new al_(var0, (int) ((long) var0._j * 256L * (long) 100 / (100L * SampledAudioChannel.SAMPLES_PER_SECOND)), volume << 6, 0x2000); + } + } + + private static int a240(final byte[] var2, final int[] var3, int var4, int var5, int var6, int var7, final int var8, final int var9, final int var11, final int var12, final al_ var13, final int var14, final int var15) { + var13._s -= var13._p * var5; + int var10; + if (var14 == 0 || (var10 = var5 + (var12 - var4 + var14 - 257) / var14) > var11) { + var10 = var11; + } + + var5 <<= 1; + + byte var16; + int var10001; + int var0; + int var1; + for (var10 <<= 1; var5 < var10; var4 += var14) { + var1 = var4 >> 8; + var16 = var2[var1]; + var0 = (var16 << 8) + (var2[var1 + 1] - var16) * (var4 & 255); + var10001 = var5++; + var3[var10001] += var0 * var6 >> 6; + var6 += var8; + var10001 = var5++; + var3[var10001] += var0 * var7 >> 6; + var7 += var9; + } + + if (var14 == 0 || (var10 = (var5 >> 1) + (var12 - var4 + var14 - 1) / var14) > var11) { + var10 = var11; + } + + var10 <<= 1; + + for (var1 = var15; var5 < var10; var4 += var14) { + var16 = var2[var4 >> 8]; + var0 = (var16 << 8) + (var1 - var16) * (var4 & 255); + var10001 = var5++; + var3[var10001] += var0 * var6 >> 6; + var6 += var8; + var10001 = var5++; + var3[var10001] += var0 * var7 >> 6; + var7 += var9; + } + + var5 >>= 1; + var13._s += var13._p * var5; + var13._y = var6; + var13._m = var7; + var13._t = var4; + return var5; + } + + private static int a775(final byte[] var1, final int[] var2, int var3, int var4, int var5, int var6, final int var8, int var9, final al_ var10) { + var3 >>= 8; + var9 >>= 8; + var5 <<= 2; + var6 <<= 2; + int var7; + if ((var7 = var4 + var3 - (var9 - 1)) > var8) { + var7 = var8; + } + + var4 <<= 1; + var7 <<= 1; + + int var10001; + byte var11; + for (var7 -= 6; var4 < var7; var2[var10001] += var11 * var6) { + var11 = var1[var3--]; + var10001 = var4++; + var2[var10001] += var11 * var5; + var10001 = var4++; + var2[var10001] += var11 * var6; + var11 = var1[var3--]; + var10001 = var4++; + var2[var10001] += var11 * var5; + var10001 = var4++; + var2[var10001] += var11 * var6; + var11 = var1[var3--]; + var10001 = var4++; + var2[var10001] += var11 * var5; + var10001 = var4++; + var2[var10001] += var11 * var6; + var11 = var1[var3--]; + var10001 = var4++; + var2[var10001] += var11 * var5; + var10001 = var4++; + } + + for (var7 += 6; var4 < var7; var2[var10001] += var11 * var6) { + var11 = var1[var3--]; + var10001 = var4++; + var2[var10001] += var11 * var5; + var10001 = var4++; + } + + var10._t = var3 << 8; + return var4 >> 1; + } + + private static int d080(final int var0, final int var1) { + return var1 < 0 ? -var0 : (int) ((double) var0 * Math.sqrt((double) var1 * 1.220703125E-4D) + 0.5D); + } + + private static int b240(final byte[] var2, final int[] var3, int var4, int var5, int var6, int var7, final int var8, final int var9, final int var11, final int var12, final al_ var13, final int var14, final int var15) { + var13._s -= var13._p * var5; + int var10; + if (var14 == 0 || (var10 = var5 + (var12 + 256 - var4 + var14) / var14) > var11) { + var10 = var11; + } + + var5 <<= 1; + + int var10001; + int var0; + int var1; + for (var10 <<= 1; var5 < var10; var4 += var14) { + var1 = var4 >> 8; + final byte var16 = var2[var1 - 1]; + var0 = (var16 << 8) + (var2[var1] - var16) * (var4 & 255); + var10001 = var5++; + var3[var10001] += var0 * var6 >> 6; + var6 += var8; + var10001 = var5++; + var3[var10001] += var0 * var7 >> 6; + var7 += var9; + } + + if (var14 == 0 || (var10 = (var5 >> 1) + (var12 - var4 + var14) / var14) > var11) { + var10 = var11; + } + + var10 <<= 1; + + for (var1 = var15; var5 < var10; var4 += var14) { + var0 = (var1 << 8) + (var2[var4 >> 8] - var1) * (var4 & 255); + var10001 = var5++; + var3[var10001] += var0 * var6 >> 6; + var6 += var8; + var10001 = var5++; + var3[var10001] += var0 * var7 >> 6; + var7 += var9; + } + + var5 >>= 1; + var13._s += var13._p * var5; + var13._y = var6; + var13._m = var7; + var13._t = var4; + return var5; + } + + private static int e080(final int var0, final int var1) { + return var1 < 0 ? var0 : (int) ((double) var0 * Math.sqrt((double) (16384 - var1) * 1.220703125E-4D) + 0.5D); + } + + private synchronized void c093(final int volume, final int var2) { + this.volume = volume; + this._z = var2; + this._v = 0; + this.k797(); + } + + private int b682(final int[] var1, int var2, final int var3, final int var4, final int var5) { + while (true) { + if (this._v > 0) { + int var6 = var2 + this._v; + if (var6 > var4) { + var6 = var4; + } + + this._v += var2; + if (this._l == 256 && (this._t & 255) == 0) { + var2 = a961(this._k.data, var1, this._t, var2, this._y, this._m, this._x, this._n, var6, var3, this); + } else { + var2 = a240(this._k.data, var1, this._t, var2, this._y, this._m, this._x, this._n, var6, var3, this, this._l, var5); + } + + this._v -= var2; + if (this._v != 0) { + return var2; + } + + if (!this.h801()) { + continue; + } + + return var4; + } + + if (this._l == 256 && (this._t & 255) == 0) { + return b775(this._k.data, var1, this._t, var2, this._y, this._m, var4, var3, this); + + } + + return d984(this._k.data, var1, this._t, var2, this._y, this._m, var4, var3, this, this._l, var5); + + } + } + + public synchronized int getVolume() { + return this.volume == Integer.MIN_VALUE ? 0 : this.volume; + } + + public synchronized void a093(final int var1, final int var2) { + this.a326(var1, var2, this.l784()); + } + + public synchronized void h150(int var1) { + final int var2 = this._k.data.length << 8; + if (var1 < -1) { + var1 = -1; + } + + if (var1 > var2) { + var1 = var2; + } + + this._t = var1; + } + + public synchronized void g150(int var1) { + if (var1 == 0) { + this.setVolume(0); + this.unlink(); + } else if (this._y == 0 && this._m == 0) { + this._v = 0; + this.volume = 0; + this._s = 0; + this.unlink(); + } else { + int var2 = -this._s; + if (this._s > var2) { + var2 = this._s; + } + + if (-this._y > var2) { + var2 = -this._y; + } + + if (this._y > var2) { + var2 = this._y; + } + + if (-this._m > var2) { + var2 = -this._m; + } + + if (this._m > var2) { + var2 = this._m; + } + + if (var1 > var2) { + var1 = var2; + } + + this._v = var1; + this.volume = Integer.MIN_VALUE; + this._p = -this._s / var1; + this._x = -this._y / var1; + this._n = -this._m / var1; + } + } + + private void k797() { + this._s = this.volume; + this._y = e080(this.volume, this._z); + this._m = d080(this.volume, this._z); + } + + public synchronized boolean e801() { + return this._v != 0; + } + + public synchronized void c487() { + this._l = (this._l ^ this._l >> 31) + (this._l >>> 31); + this._l = -this._l; + + } + + @Override + public synchronized void a150(int len) { + if (this._v > 0) { + if (len >= this._v) { + if (this.volume == Integer.MIN_VALUE) { + this.volume = 0; + this._m = 0; + this._y = 0; + this._s = 0; + this.unlink(); + len = this._v; + } + + this._v = 0; + this.k797(); + } else { + this._s += this._p * len; + this._y += this._x * len; + this._m += this._n * len; + this._v -= len; + } + } + + final kk_ var2 = this._k; + final int var3 = this._u << 8; + final int var4 = this._r << 8; + final int var5 = var2.data.length << 8; + final int var6 = var4 - var3; + if (var6 <= 0) { + this._q = 0; + } + + if (this._t < 0) { + if (this._l <= 0) { + this.j797(); + this.unlink(); + return; + } + + this._t = 0; + } + + if (this._t >= var5) { + if (this._l >= 0) { + this.j797(); + this.unlink(); + return; + } + + this._t = var5 - 1; + } + + this._t += this._l * len; + if (this._q < 0) { + if (this._o) { + if (this._l < 0) { + if (this._t >= var3) { + return; + } + + this._t = var3 + var3 - 1 - this._t; + this._l = -this._l; + } + + while (this._t >= var4) { + this._t = var4 + var4 - 1 - this._t; + this._l = -this._l; + if (this._t >= var3) { + return; + } + + this._t = var3 + var3 - 1 - this._t; + this._l = -this._l; + } + + } else if (this._l < 0) { + if (this._t >= var3) { + return; + } + + this._t = var4 - 1 - (var4 - 1 - this._t) % var6; + } else { + if (this._t < var4) { + return; + } + + this._t = var3 + (this._t - var3) % var6; + } + } else { + if (this._q > 0) { + label121: + { + if (this._l < 0) { + if (this._t >= var3) { + return; + } + + this._t = var3 + var3 - 1 - this._t; + this._l = -this._l; + if (--this._q == 0) { + break label121; + } + } + + do { + if (this._t < var4) { + return; + } + + this._t = var4 + var4 - 1 - this._t; + this._l = -this._l; + if (--this._q == 0) { + break; + } + + if (this._t >= var3) { + return; + } + + this._t = var3 + var3 - 1 - this._t; + this._l = -this._l; + } while (--this._q != 0); + } + } + + if (this._l < 0) { + if (this._t < 0) { + this._t = -1; + this.j797(); + this.unlink(); + } + } else if (this._t >= var5) { + this._t = var5; + this.j797(); + this.unlink(); + } + } + } + + public synchronized boolean g801() { + return this._t < 0 || this._t >= this._k.data.length << 8; + } + + public synchronized void a326(int var1, final int var2, final int var3) { + if (var1 == 0) { + this.c093(var2, var3); + } else { + final int var4 = e080(var2, var3); + final int var5 = d080(var2, var3); + if (this._y == var4 && this._m == var5) { + this._v = 0; + } else { + int var6 = var2 - this._s; + if (this._s - var2 > var6) { + var6 = this._s - var2; + } + + if (var4 - this._y > var6) { + var6 = var4 - this._y; + } + + if (this._y - var4 > var6) { + var6 = this._y - var4; + } + + if (var5 - this._m > var6) { + var6 = var5 - this._m; + } + + if (this._m - var5 > var6) { + var6 = this._m - var5; + } + + if (var1 > var6) { + var1 = var6; + } + + this._v = var1; + this.volume = var2; + this._z = var3; + this._p = (var2 - this._s) / var1; + this._x = (var4 - this._y) / var1; + this._n = (var5 - this._m) / var1; + } + } + } + + @Override + public @NotNull Iterator iterator() { + return Collections.emptyIterator(); + } + + @Override + public int a784() { + return this.volume == 0 && this._v == 0 ? 0 : 1; + } + + public synchronized void d150(final int var1) { + if (this._l < 0) { + this._l = -var1; + } else { + this._l = var1; + } + + } + + @Override + public synchronized void b397(final int[] dest, final int offset, final int len) { + if (this.volume == 0 && this._v == 0) { + this.a150(len); + return; + } + + final int var5 = this._u << 8; + final int var6 = this._r << 8; + final int var7 = this._k.data.length << 8; + final int var8 = var6 - var5; + if (var8 <= 0) { + this._q = 0; + } + + int pos = offset; + final int end = len + offset; + if (this._t < 0) { + if (this._l <= 0) { + this.j797(); + this.unlink(); + return; + } + + this._t = 0; + } + + if (this._t >= var7) { + if (this._l >= 0) { + this.j797(); + this.unlink(); + return; + } + + this._t = var7 - 1; + } + + if (this._q < 0) { + if (this._o) { + if (this._l < 0) { + pos = this.a682(dest, offset, var5, end, this._k.data[this._u]); + if (this._t >= var5) { + return; + } + + this._t = var5 + var5 - 1 - this._t; + this._l = -this._l; + } + + while (true) { + pos = this.b682(dest, pos, var6, end, this._k.data[this._r - 1]); + if (this._t < var6) { + return; + } + + this._t = var6 + var6 - 1 - this._t; + this._l = -this._l; + pos = this.a682(dest, pos, var5, end, this._k.data[this._u]); + if (this._t >= var5) { + return; + } + + this._t = var5 + var5 - 1 - this._t; + this._l = -this._l; + } + } else if (this._l < 0) { + while (true) { + pos = this.a682(dest, pos, var5, end, this._k.data[this._r - 1]); + if (this._t >= var5) { + return; + } + + this._t = var6 - 1 - (var6 - 1 - this._t) % var8; + } + } else { + while (true) { + pos = this.b682(dest, pos, var6, end, this._k.data[this._u]); + if (this._t < var6) { + return; + } + + this._t = var5 + (this._t - var5) % var8; + } + } + } else { + if (this._q > 0) { + if (this._o) { + label131: + { + if (this._l < 0) { + pos = this.a682(dest, offset, var5, end, this._k.data[this._u]); + if (this._t >= var5) { + return; + } + + this._t = var5 + var5 - 1 - this._t; + this._l = -this._l; + if (--this._q == 0) { + break label131; + } + } + + do { + pos = this.b682(dest, pos, var6, end, this._k.data[this._r - 1]); + if (this._t < var6) { + return; + } + + this._t = var6 + var6 - 1 - this._t; + this._l = -this._l; + if (--this._q == 0) { + break; + } + + pos = this.a682(dest, pos, var5, end, this._k.data[this._u]); + if (this._t >= var5) { + return; + } + + this._t = var5 + var5 - 1 - this._t; + this._l = -this._l; + } while (--this._q != 0); + } + } else { + int var10; + if (this._l < 0) { + while (true) { + pos = this.a682(dest, pos, var5, end, this._k.data[this._r - 1]); + if (this._t >= var5) { + return; + } + + var10 = (var6 - 1 - this._t) / var8; + if (var10 >= this._q) { + this._t += var8 * this._q; + this._q = 0; + break; + } + + this._t += var8 * var10; + this._q -= var10; + } + } else { + while (true) { + pos = this.b682(dest, pos, var6, end, this._k.data[this._u]); + if (this._t < var6) { + return; + } + + var10 = (this._t - var5) / var8; + if (var10 >= this._q) { + this._t -= var8 * this._q; + this._q = 0; + break; + } + + this._t -= var8 * var10; + this._q -= var10; + } + } + } + } + + if (this._l < 0) { + this.a682(dest, pos, 0, end, 0); + if (this._t < 0) { + this._t = -1; + this.j797(); + this.unlink(); + } + } else { + this.b682(dest, pos, var7, end, 0); + if (this._t >= var7) { + this._t = var7; + this.j797(); + this.unlink(); + } + } + } + } + + @Override + public int c784() { + final int var1 = (this._s * 3) >> 6; + int var2 = (var1 ^ (var1 >> 31)) + (var1 >>> 31); + if (this._q == 0) { + var2 -= var2 * this._t / (this._k.data.length << 8); + } else if (this._q >= 0) { + var2 -= var2 * this._u / this._k.data.length; + } + return Math.min(var2, 255); + } + + private void j797() { + if (this._v != 0) { + if (this.volume == Integer.MIN_VALUE) { + this.volume = 0; + } + + this._v = 0; + this.k797(); + } + + } + + public synchronized int f784() { + return this._l < 0 ? -this._l : this._l; + } + + private int a682(final int[] dest, int var2, final int var3, final int var4, final int var5) { + while (true) { + if (this._v > 0) { + int var6 = var2 + this._v; + if (var6 > var4) { + var6 = var4; + } + + this._v += var2; + if (this._l == -256 && (this._t & 255) == 0) { + var2 = b961(this._k.data, dest, this._t, var2, this._y, this._m, this._x, this._n, var6, var3, this); + } else { + var2 = b240(this._k.data, dest, this._t, var2, this._y, this._m, this._x, this._n, var6, var3, this, this._l, var5); + } + + this._v -= var2; + if (this._v != 0) { + return var2; + } + + if (!this.h801()) { + continue; + } + + return var4; + } + + if (this._l == -256 && (this._t & 255) == 0) { + return a775(this._k.data, dest, this._t, var2, this._y, this._m, var4, var3, this); + + } + + return c984(this._k.data, dest, this._t, var2, this._y, this._m, var4, var3, this, this._l, var5); + + } + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + private boolean h801() { + int var1 = this.volume; + final int var2; + final int var3; + if (var1 == Integer.MIN_VALUE) { + var3 = 0; + var2 = 0; + var1 = 0; + } else { + var2 = e080(var1, this._z); + var3 = d080(var1, this._z); + } + + if (this._s == var1 && this._y == var2 && this._m == var3) { + if (this.volume == Integer.MIN_VALUE) { + this.volume = 0; + this.unlink(); + return true; + } else { + this.k797(); + return false; + } + } else { + if (this._s < var1) { + this._p = 1; + this._v = var1 - this._s; + } else if (this._s > var1) { + this._p = -1; + this._v = this._s - var1; + } else { + this._p = 0; + } + + if (this._y < var2) { + this._x = 1; + if (this._v == 0 || this._v > var2 - this._y) { + this._v = var2 - this._y; + } + } else if (this._y > var2) { + this._x = -1; + if (this._v == 0 || this._v > this._y - var2) { + this._v = this._y - var2; + } + } else { + this._x = 0; + } + + if (this._m < var3) { + this._n = 1; + if (this._v == 0 || this._v > var3 - this._m) { + this._v = var3 - this._m; + } + } else if (this._m > var3) { + this._n = -1; + if (this._v == 0 || this._v > this._m - var3) { + this._v = this._m - var3; + } + } else { + this._n = 0; + } + + return false; + } + } + + public synchronized int l784() { + return this._z < 0 ? -1 : this._z; + } + + public synchronized void setVolume(final int volume) { + this.c093(volume, this.l784()); + } + + public synchronized void f150() { + this._q = -1; + } +} diff --git a/src/main/java/funorb/audio/br_.java b/src/main/java/funorb/audio/br_.java new file mode 100644 index 0000000..9decab9 --- /dev/null +++ b/src/main/java/funorb/audio/br_.java @@ -0,0 +1,490 @@ +package funorb.audio; + +import funorb.io.Buffer; + +public final class br_ { + public final kk_[] _h = new kk_[128]; + public final kc_[] _j = new kc_[128]; + public final byte[] _t = new byte[128]; + public final int _q; + public final short[] _k = new short[128]; + public final byte[] _r = new byte[128]; + public final byte[] _s = new byte[128]; + private int[] _n = new int[128]; + + public br_(final byte[] var1) { + final Buffer var2 = new Buffer(var1); + + int var3 = 0; + while (var2.data[var3 + var2.pos] != 0) { + ++var3; + } + + final byte[] var4 = new byte[var3]; + + int var5; + for (var5 = 0; var5 < var3; ++var5) { + var4[var5] = var2.readByte(); + } + + ++var3; + ++var2.pos; + var5 = var2.pos; + var2.pos += var3; + + int var6 = 0; + while (var2.data[var6 + var2.pos] != 0) { + ++var6; + } + + final byte[] var7 = new byte[var6]; + + int var8; + for (var8 = 0; var8 < var6; ++var8) { + var7[var8] = var2.readByte(); + } + + ++var2.pos; + ++var6; + var8 = var2.pos; + var2.pos += var6; + + int var9 = 0; + while (var2.data[var9 + var2.pos] != 0) { + ++var9; + } + + final byte[] var10 = new byte[var9]; + + for (int var11 = 0; var11 < var9; ++var11) { + var10[var11] = var2.readByte(); + } + + ++var9; + ++var2.pos; + final byte[] var36 = new byte[var9]; + int var12; + int var14; + if (var9 <= 1) { + var12 = var9; + } else { + var36[1] = 1; + var12 = 2; + int var13 = 1; + + for (var14 = 2; var9 > var14; ++var14) { + int var15 = var2.readUByte(); + if (var15 == 0) { + var13 = var12++; + } else { + if (var13 >= var15) { + --var15; + } + + var13 = var15; + } + + var36[var14] = (byte) var13; + } + } + + final kc_[] var37 = new kc_[var12]; + + kc_ var38; + for (var14 = 0; var14 < var37.length; ++var14) { + var38 = var37[var14] = new kc_(); + final int var16 = var2.readUByte(); + if (var16 > 0) { + var38._n = new byte[var16 * 2]; + } + + final int j137 = var2.readUByte(); + if (j137 > 0) { + var38._e = new byte[2 * j137 + 2]; + var38._e[1] = 64; + } + } + + var14 = var2.readUByte(); + final byte[] var39 = var14 > 0 ? new byte[2 * var14] : null; + var14 = var2.readUByte(); + final byte[] var40 = var14 <= 0 ? null : new byte[var14 * 2]; + + int var17 = 0; + while (var2.data[var2.pos + var17] != 0) { + ++var17; + } + + final byte[] var18 = new byte[var17]; + + int var19; + for (var19 = 0; var19 < var17; ++var19) { + var18[var19] = var2.readByte(); + } + + ++var17; + ++var2.pos; + var19 = 0; + + int var20; + for (var20 = 0; var20 < 128; ++var20) { + var19 += var2.readUByte(); + this._k[var20] = (short) var19; + } + + var19 = 0; + + for (var20 = 0; var20 < 128; ++var20) { + var19 += var2.readUByte(); + this._k[var20] = (short) (this._k[var20] + (var19 << 8)); + } + + var20 = 0; + int var21 = 0; + int var22 = 0; + + int var23; + for (var23 = 0; var23 < 128; ++var23) { + if (var20 == 0) { + if (var18.length <= var21) { + var20 = -1; + } else { + var20 = var18[var21++]; + } + + var22 = var2.readVariableInt(); + } + + this._k[var23] = (short) (this._k[var23] + ((var22 - 1 & 2) << 14)); + --var20; + this._n[var23] = var22; + } + + int i = 0; + var20 = 0; + var23 = 0; + + int var24; + for (var24 = 0; var24 < 128; ++var24) { + if (this._n[var24] != 0) { + if (var20 == 0) { + if (i < var4.length) { + var20 = var4[i++]; + } else { + var20 = -1; + } + + var23 = var2.data[var5++] - 1; + } + + --var20; + this._r[var24] = (byte) var23; + } + } + + int i1 = 0; + var20 = 0; + var24 = 0; + + for (int var25 = 0; var25 < 128; ++var25) { + if (this._n[var25] != 0) { + if (var20 == 0) { + if (i1 >= var7.length) { + var20 = -1; + } else { + var20 = var7[i1++]; + } + + var24 = 16 + var2.data[var8++] << 2; + } + + --var20; + this._t[var25] = (byte) var24; + } + } + + int i2 = 0; + var20 = 0; + kc_ var42 = null; + + int var26; + for (var26 = 0; var26 < 128; ++var26) { + if (this._n[var26] != 0) { + if (var20 == 0) { + var42 = var37[var36[i2]]; + if (var10.length <= i2) { + var20 = -1; + } else { + var20 = var10[i2++]; + } + } + + --var20; + this._j[var26] = var42; + } + } + + int i3 = 0; + var20 = 0; + var26 = 0; + + int var27; + for (var27 = 0; var27 < 128; ++var27) { + if (var20 == 0) { + if (i3 < var18.length) { + var20 = var18[i3++]; + } else { + var20 = -1; + } + + if (this._n[var27] > 0) { + var26 = var2.readUByte() + 1; + } + } + + --var20; + this._s[var27] = (byte) var26; + } + + this._q = var2.readUByte() + 1; + + kc_ var28; + int var29; + for (var27 = 0; var27 < var12; ++var27) { + var28 = var37[var27]; + if (var28._n != null) { + for (var29 = 1; var29 < var28._n.length; var29 += 2) { + var28._n[var29] = var2.readByte(); + } + } + + if (var28._e != null) { + for (var29 = 3; var28._e.length - 2 > var29; var29 += 2) { + var28._e[var29] = var2.readByte(); + } + } + } + + if (var39 != null) { + for (var27 = 1; var39.length > var27; var27 += 2) { + var39[var27] = var2.readByte(); + } + } + + if (var40 != null) { + for (var27 = 1; var27 < var40.length; var27 += 2) { + var40[var27] = var2.readByte(); + } + } + + for (var27 = 0; var27 < var12; ++var27) { + var28 = var37[var27]; + if (var28._e != null) { + var19 = 0; + + for (var29 = 2; var29 < var28._e.length; var29 += 2) { + var19 = var2.readUByte() + var19 + 1; + var28._e[var29] = (byte) var19; + } + } + } + + for (var27 = 0; var12 > var27; ++var27) { + var28 = var37[var27]; + if (var28._n != null) { + var19 = 0; + + for (var29 = 2; var29 < var28._n.length; var29 += 2) { + var19 = var2.readUByte() + var19 + 1; + var28._n[var29] = (byte) var19; + } + } + } + + byte var30; + int var32; + int var33; + int var34; + int var45; + byte var47; + if (var39 != null) { + var19 = var2.readUByte(); + var39[0] = (byte) var19; + + for (var27 = 2; var27 < var39.length; var27 += 2) { + var19 = var2.readUByte() + var19 + 1; + var39[var27] = (byte) var19; + } + + var47 = var39[0]; + byte var43 = var39[1]; + + for (var29 = 0; var29 < var47; ++var29) { + this._s[var29] = (byte) (32 + this._s[var29] * var43 >> 6); + } + + for (var29 = 2; var29 < var39.length; var47 = var30) { + var30 = var39[var29]; + final byte var31 = var39[var29 + 1]; + var32 = (-var47 + var30) / 2 + var43 * (var30 - var47); + + for (var33 = var47; var30 > var33; ++var33) { + var34 = a666ql(var32, var30 - var47); + this._s[var33] = (byte) (32 + this._s[var33] * var34 >> 6); + var32 += -var43 + var31; + } + + var43 = var31; + var29 += 2; + } + + for (var45 = var47; var45 < 128; ++var45) { + this._s[var45] = (byte) (32 + this._s[var45] * var43 >> 6); + } + } + + if (var40 != null) { + var19 = var2.readUByte(); + var40[0] = (byte) var19; + + for (var27 = 2; var40.length > var27; var27 += 2) { + var19 = 1 + var19 + var2.readUByte(); + var40[var27] = (byte) var19; + } + + var47 = var40[0]; + int var44 = var40[1] << 1; + + for (var29 = 0; var29 < var47; ++var29) { + var45 = (this._t[var29] & 255) + var44; + if (var45 < 0) { + var45 = 0; + } + + if (var45 > 128) { + var45 = 128; + } + + this._t[var29] = (byte) var45; + } + + int var46; + for (var29 = 2; var40.length > var29; var44 = var46) { + var30 = var40[var29]; + var46 = var40[1 + var29] << 1; + var32 = (-var47 + var30) / 2 + (var30 - var47) * var44; + + for (var33 = var47; var33 < var30; ++var33) { + var34 = a666ql(var32, -var47 + var30); + int var35 = var34 + (255 & this._t[var33]); + if (var35 < 0) { + var35 = 0; + } + + if (var35 > 128) { + var35 = 128; + } + + this._t[var33] = (byte) var35; + var32 += -var44 + var46; + } + + var47 = var30; + var29 += 2; + } + + for (var45 = var47; var45 < 128; ++var45) { + var46 = var44 + (this._t[var45] & 255); + if (var46 < 0) { + var46 = 0; + } + + if (var46 > 128) { + var46 = 128; + } + + this._t[var45] = (byte) var46; + } + } + + for (var27 = 0; var12 > var27; ++var27) { + var37[var27]._h = var2.readUByte(); + } + + for (var27 = 0; var12 > var27; ++var27) { + var28 = var37[var27]; + if (var28._n != null) { + var28._k = var2.readUByte(); + } + + if (var28._e != null) { + var28._c = var2.readUByte(); + } + + if (var28._h > 0) { + var28._a = var2.readUByte(); + } + } + + for (var27 = 0; var27 < var12; ++var27) { + var37[var27]._o = var2.readUByte(); + } + + for (var27 = 0; var12 > var27; ++var27) { + var28 = var37[var27]; + if (var28._o > 0) { + var28._f = var2.readUByte(); + } + } + + for (var27 = 0; var12 > var27; ++var27) { + var28 = var37[var27]; + if (var28._f > 0) { + var28._j = var2.readUByte(); + } + } + + } + + private static int a666ql(final int var0, final int var1) { + final int var2 = var0 >>> 31; + return -var2 + (var0 + var2) / var1; + } + + public boolean a972(final SoundLoader var1, final byte[] var2) { + boolean var5 = true; + int var6 = 0; + kk_ var7 = null; + + for (int var8 = 0; var8 < 128; ++var8) { + if (var2 == null || var2[var8] != 0) { + int var9 = this._n[var8]; + if (var9 != 0) { + if (var9 != var6) { + var6 = var9--; + if ((1 & var9) == 0) { + var7 = var1.loadSingleton1(var9 >> 2); + } else { + var7 = var1.loadSingleton2(var9 >> 2); + } + + if (var7 == null) { + var5 = false; + } + } + + if (var7 != null) { + this._h[var8] = var7; + this._n[var8] = 0; + } + } + } + } + + return var5; + } + + public void e150() { + this._n = null; + } +} diff --git a/src/main/java/funorb/audio/dq_.java b/src/main/java/funorb/audio/dq_.java new file mode 100644 index 0000000..ec7bbf1 --- /dev/null +++ b/src/main/java/funorb/audio/dq_.java @@ -0,0 +1,69 @@ +package funorb.audio; + +import funorb.cache.ResourceLoader; +import funorb.io.Buffer; + +public final class dq_ { + private final pk_[] _b = new pk_[10]; + private final int _c; + private final int _a; + + private dq_(final Buffer data) { + for (int i = 0; i < 10; ++i) { + final int var3 = data.readUByte(); + if (var3 != 0) { + --data.pos; + this._b[i] = new pk_(); + this._b[i].initialize(data); + } + } + + this._c = data.readUShort(); + this._a = data.readUShort(); + } + + public static dq_ load(final ResourceLoader loader, final int groupId, final int itemId) { + final byte[] data = loader.getResource(groupId, itemId); + return data == null ? null : new dq_(new Buffer(data)); + } + + private byte[] a928() { + int var1 = 0; + + for (int i = 0; i < 10; ++i) { + if (this._b[i] != null && var1 < this._b[i]._a + this._b[i]._s) { + var1 = this._b[i]._a + this._b[i]._s; + } + } + + if (var1 == 0) { + return new byte[0]; + } + final int var2 = SampledAudioChannel.SAMPLES_PER_SECOND * var1 / 1000; + final byte[] var3 = new byte[var2]; + + for (int i = 0; i < 10; ++i) { + if (this._b[i] != null) { + final int var5 = this._b[i]._a * SampledAudioChannel.SAMPLES_PER_SECOND / 1000; + final int var6 = this._b[i]._s * SampledAudioChannel.SAMPLES_PER_SECOND / 1000; + final int[] var7 = this._b[i].a111(var5, this._b[i]._a); + + for (int j = 0; j < var5; ++j) { + int var9 = var3[j + var6] + (var7[j] >> 8); + if ((var9 + 128 & -256) != 0) { + var9 = var9 >> 31 ^ 127; + } + + var3[j + var6] = (byte) var9; + } + } + } + + return var3; + } + + public kk_ b720() { + final byte[] var1 = this.a928(); + return new kk_(var1, SampledAudioChannel.SAMPLES_PER_SECOND * this._c / 1000, SampledAudioChannel.SAMPLES_PER_SECOND * this._a / 1000); + } +} diff --git a/src/main/java/funorb/audio/fd_.java b/src/main/java/funorb/audio/fd_.java new file mode 100644 index 0000000..de67dcd --- /dev/null +++ b/src/main/java/funorb/audio/fd_.java @@ -0,0 +1,598 @@ +package funorb.audio; + +import funorb.cache.ResourceLoader; +import funorb.io.Buffer; +import funorb.util.BitMath; + +import java.io.IOException; +import java.util.stream.IntStream; + +public final class fd_ { + public static vb_[] _L; + private static float[] _k; + private static to_[] _o; + private static int[] _J; + private static int[] _D; + private static fq_[] _O; + private static float[] _u; + private static float[] _C; + private static boolean _x = false; + private static byte[] _w; + private static float[] _z; + private static boolean[] _t; + private static float[] _y; + private static float[] _j; + private static int _r; + private static float[] _l; + private static int _K; + private static int[] _F; + private static int _E; + private static kn_[] _h; + private static int _p; + private int _q; + private int _G; + private boolean _I; + private int _H; + private int _i; + private int _s; + private boolean _A; + private byte[][] _v; + private int _M; + private int _B; + private byte[] _N; + private float[] _n; + private int _m; + + private fd_(final byte[] var1) throws IOException { + this.a604(var1); + } + + public static float d134(final int var0) { + int var1 = var0 & 2097151; + final int var2 = var0 & Integer.MIN_VALUE; + final int var3 = (var0 & 2145386496) >> 21; + if (var2 != 0) { + var1 = -var1; + } + + return (float) ((double) var1 * Math.pow(2.0D, var3 - 788)); + } + + public static int c784() { + final int var0 = _w[_p] >> _K & 1; + ++_K; + _p += _K >> 3; + _K &= 7; + return var0; + } + + public static void b604(final byte[] var0) { + a167(var0); + _E = 1 << a137(4); + _r = 1 << a137(4); + _k = new float[_r]; + + int var1; + int var2; + int var3; + int var4; + int var5; + for (var1 = 0; var1 < 2; ++var1) { + var2 = var1 != 0 ? _r : _E; + var3 = var2 >> 1; + var4 = var2 >> 2; + var5 = var2 >> 3; + final float[] var6 = new float[var3]; + + for (int var7 = 0; var7 < var4; ++var7) { + var6[2 * var7] = (float) Math.cos((double) (4 * var7) * Math.PI / (double) var2); + var6[2 * var7 + 1] = -((float) Math.sin((double) (4 * var7) * Math.PI / (double) var2)); + } + + final float[] var13 = new float[var3]; + + for (int var8 = 0; var8 < var4; ++var8) { + var13[2 * var8] = (float) Math.cos((double) (2 * var8 + 1) * Math.PI / (double) (2 * var2)); + var13[2 * var8 + 1] = (float) Math.sin((double) (2 * var8 + 1) * Math.PI / (double) (2 * var2)); + } + + final float[] var14 = new float[var4]; + + for (int var9 = 0; var9 < var5; ++var9) { + var14[2 * var9] = (float) Math.cos((double) (4 * var9 + 2) * Math.PI / (double) var2); + var14[2 * var9 + 1] = -((float) Math.sin((double) (4 * var9 + 2) * Math.PI / (double) var2)); + } + + final int var10 = BitMath.lastSet(var5 - 1); + final int[] var15 = IntStream.range(0, var5).map(var11 -> a586js(var11, var10)).toArray(); + + if (var1 == 0) { + _l = var6; + _z = var13; + _C = var14; + _D = var15; + } else { + _j = var6; + _y = var13; + _u = var14; + _F = var15; + } + } + + var1 = a137(8) + 1; + _L = new vb_[var1]; + + for (var2 = 0; var2 < var1; ++var2) { + _L[var2] = new vb_(); + } + + var2 = a137(6) + 1; + + for (var3 = 0; var3 < var2; ++var3) { + a137(16); + } + + var2 = a137(6) + 1; + _h = new kn_[var2]; + + for (var3 = 0; var3 < var2; ++var3) { + _h[var3] = new kn_(); + } + + var3 = a137(6) + 1; + _o = new to_[var3]; + + for (var4 = 0; var4 < var3; ++var4) { + _o[var4] = new to_(); + } + + var4 = a137(6) + 1; + _O = new fq_[var4]; + + for (var5 = 0; var5 < var4; ++var5) { + _O[var5] = new fq_(); + } + + var5 = a137(6) + 1; + _t = new boolean[var5]; + _J = new int[var5]; + + for (int var12 = 0; var12 < var5; ++var12) { + _t[var12] = c784() != 0; + a137(16); + a137(16); + _J[var12] = a137(8); + } + + _x = true; + } + + @SuppressWarnings("SameParameterValue") + public static fd_ a968(final ResourceLoader loader, final String group, final String item) { + if (a521(loader)) { + final byte[] var3 = loader.getResource(group, item); + if (var3 == null) { + return null; + } else { + fd_ var4 = null; + + try { + var4 = new fd_(var3); + } catch (final IOException var6) { + var6.printStackTrace(); + } + + return var4; + } + } else { + loader.loadGroupDataForItem(group, item); + return null; + } + } + + private static boolean a521(final ResourceLoader var0) { + if (!_x) { + final byte[] var1 = var0.getResource(0, 0); + if (var1 == null) { + return false; + } + + b604(var1); + } + + return true; + } + + private static void a167(final byte[] var0) { + _w = var0; + _p = 0; + _K = 0; + } + + public static int a137(int var0) { + int var1 = 0; + + int var2; + int var3; + for (var2 = 0; var0 >= 8 - _K; var0 -= var3) { + var3 = 8 - _K; + final int var4 = (1 << var3) - 1; + var1 += (_w[_p] >> _K & var4) << var2; + _K = 0; + ++_p; + var2 += var3; + } + + if (var0 > 0) { + var3 = (1 << var0) - 1; + var1 += (_w[_p] >> _K & var3) << var2; + _K += var0; + } + + return var1; + } + + public static fd_ a740(final ResourceLoader var0, final int var1, final int var2) { + if (a521(var0)) { + final byte[] var3 = var0.getResource(var1, var2); + if (var3 == null) { + return null; + } else { + fd_ var4 = null; + + try { + var4 = new fd_(var3); + } catch (final IOException var6) { + var6.printStackTrace(); + } + + return var4; + } + } else { + var0.loadGroupDataForItem(var1, var2); + return null; + } + } + + private static int a586js(int var0, int var1) { + int var2; + for (var2 = 0; var1 > 0; var0 >>>= 1) { + var2 = var2 << 1 | 1 & var0; + --var1; + } + + return var2; + } + + public kk_ a582() { + if (this._N == null) { + this._M = 0; + this._n = new float[_r]; + this._N = new byte[this._q]; + this._s = 0; + this._m = 0; + } + + for (; this._m < this._v.length; ++this._m) { + + final float[] var2 = this.e875(this._m); + if (var2 != null) { + int var3 = this._s; + int var4 = var2.length; + if (var4 > this._q - var3) { + var4 = this._q - var3; + } + + for (int var5 = 0; var5 < var4; ++var5) { + int var6 = (int) (128.0F + var2[var5] * 128.0F); + if ((var6 & -256) != 0) { + var6 = ~var6 >> 31; + } + + this._N[var3++] = (byte) (var6 - 128); + } + + this._s = var3; + } + } + + this._n = null; + final byte[] var7 = this._N; + this._N = null; + return new kk_(this._B, var7, this._H, this._G, this._I); + } + + private float[] e875(final int var1) { + a167(this._v[var1]); + c784(); + final int var2 = a137(BitMath.lastSet(_J.length - 1)); + final boolean var3 = _t[var2]; + final int var4 = var3 ? _r : _E; + boolean var5 = false; + boolean var6 = false; + if (var3) { + var5 = c784() != 0; + var6 = c784() != 0; + } + + final int var7 = var4 >> 1; + final int var8; + final int var9; + final int var10; + if (var3 && !var5) { + var8 = (var4 >> 2) - (_E >> 2); + var9 = (var4 >> 2) + (_E >> 2); + var10 = _E >> 1; + } else { + var8 = 0; + var9 = var7; + var10 = var4 >> 1; + } + + final int var11; + final int var12; + final int var13; + if (var3 && !var6) { + var11 = var4 - (var4 >> 2) - (_E >> 2); + var12 = var4 - (var4 >> 2) + (_E >> 2); + var13 = _E >> 1; + } else { + var11 = var7; + var12 = var4; + var13 = var4 >> 1; + } + + final fq_ var14 = _O[_J[var2]]; + final int var16 = var14._d; + int var17 = var14._b[var16]; + final boolean var15 = !_h[var17].b801(); + + for (var17 = 0; var17 < var14._c; ++var17) { + final to_ var18 = _o[var14._a[var17]]; + final float[] var19 = _k; + var18.a623(var19, var4 >> 1, var15); + } + + int var41; + if (!var15) { + var17 = var14._d; + var41 = var14._b[var17]; + _h[var41].a331(_k, var4 >> 1); + } + + int var42; + if (var15) { + for (var17 = var4 >> 1; var17 < var4; ++var17) { + _k[var17] = 0.0F; + } + } else { + final int i = var4 >> 1; + var41 = var4 >> 2; + var42 = var4 >> 3; + final float[] var20 = _k; + + int var21; + for (var21 = 0; var21 < i; ++var21) { + var20[var21] *= 0.5F; + } + + for (var21 = i; var21 < var4; ++var21) { + var20[var21] = -var20[var4 - var21 - 1]; + } + + final float[] var46 = var3 ? _j : _l; + final float[] var22 = var3 ? _y : _z; + final float[] var23 = var3 ? _u : _C; + final int[] var24 = var3 ? _F : _D; + + int var25; + float var26; + float var27; + float var28; + float var29; + for (var25 = 0; var25 < var41; ++var25) { + var26 = var20[4 * var25] - var20[var4 - 4 * var25 - 1]; + var27 = var20[4 * var25 + 2] - var20[var4 - 4 * var25 - 3]; + var28 = var46[2 * var25]; + var29 = var46[2 * var25 + 1]; + var20[var4 - 4 * var25 - 1] = var26 * var28 - var27 * var29; + var20[var4 - 4 * var25 - 3] = var26 * var29 + var27 * var28; + } + + float var30; + float var31; + for (var25 = 0; var25 < var42; ++var25) { + var26 = var20[i + 3 + 4 * var25]; + var27 = var20[i + 1 + 4 * var25]; + var28 = var20[4 * var25 + 3]; + var29 = var20[4 * var25 + 1]; + var20[i + 3 + 4 * var25] = var26 + var28; + var20[i + 1 + 4 * var25] = var27 + var29; + var30 = var46[i - 4 - 4 * var25]; + var31 = var46[i - 3 - 4 * var25]; + var20[4 * var25 + 3] = (var26 - var28) * var30 - (var27 - var29) * var31; + var20[4 * var25 + 1] = (var27 - var29) * var30 + (var26 - var28) * var31; + } + + var25 = BitMath.lastSet(var4 - 1); + + int var47; + int var48; + int var49; + int var50; + for (var47 = 0; var47 < var25 - 3; ++var47) { + var48 = var4 >> var47 + 2; + var49 = 8 << var47; + + for (var50 = 0; var50 < 2 << var47; ++var50) { + final int var51 = var4 - var48 * 2 * var50; + final int var52 = var4 - var48 * (2 * var50 + 1); + + for (int var32 = 0; var32 < var4 >> var47 + 4; ++var32) { + final int var33 = 4 * var32; + final float var34 = var20[var51 - 1 - var33]; + final float var35 = var20[var51 - 3 - var33]; + final float var36 = var20[var52 - 1 - var33]; + final float var37 = var20[var52 - 3 - var33]; + var20[var51 - 1 - var33] = var34 + var36; + var20[var51 - 3 - var33] = var35 + var37; + final float var38 = var46[var32 * var49]; + final float var39 = var46[var32 * var49 + 1]; + var20[var52 - 1 - var33] = (var34 - var36) * var38 - (var35 - var37) * var39; + var20[var52 - 3 - var33] = (var35 - var37) * var38 + (var34 - var36) * var39; + } + } + } + + for (var47 = 1; var47 < var42 - 1; ++var47) { + var48 = var24[var47]; + if (var47 < var48) { + var49 = 8 * var47; + var50 = 8 * var48; + var30 = var20[var49 + 1]; + var20[var49 + 1] = var20[var50 + 1]; + var20[var50 + 1] = var30; + var30 = var20[var49 + 3]; + var20[var49 + 3] = var20[var50 + 3]; + var20[var50 + 3] = var30; + var30 = var20[var49 + 5]; + var20[var49 + 5] = var20[var50 + 5]; + var20[var50 + 5] = var30; + var30 = var20[var49 + 7]; + var20[var49 + 7] = var20[var50 + 7]; + var20[var50 + 7] = var30; + } + } + + for (var47 = 0; var47 < i; ++var47) { + var20[var47] = var20[2 * var47 + 1]; + } + + for (var47 = 0; var47 < var42; ++var47) { + var20[var4 - 1 - 2 * var47] = var20[4 * var47]; + var20[var4 - 2 - 2 * var47] = var20[4 * var47 + 1]; + var20[var4 - var41 - 1 - 2 * var47] = var20[4 * var47 + 2]; + var20[var4 - var41 - 2 - 2 * var47] = var20[4 * var47 + 3]; + } + + for (var47 = 0; var47 < var42; ++var47) { + var27 = var23[2 * var47]; + var28 = var23[2 * var47 + 1]; + var29 = var20[i + 2 * var47]; + var30 = var20[i + 2 * var47 + 1]; + var31 = var20[var4 - 2 - 2 * var47]; + final float var53 = var20[var4 - 1 - 2 * var47]; + final float var54 = var28 * (var29 - var31) + var27 * (var30 + var53); + var20[i + 2 * var47] = (var29 + var31 + var54) * 0.5F; + var20[var4 - 2 - 2 * var47] = (var29 + var31 - var54) * 0.5F; + final float v = var28 * (var30 + var53) - var27 * (var29 - var31); + var20[i + 2 * var47 + 1] = (var30 - var53 + v) * 0.5F; + var20[var4 - 1 - 2 * var47] = (-var30 + var53 + v) * 0.5F; + } + + for (var47 = 0; var47 < var41; ++var47) { + var20[var47] = var20[2 * var47 + i] * var22[2 * var47] + var20[2 * var47 + 1 + i] * var22[2 * var47 + 1]; + var20[i - 1 - var47] = var20[2 * var47 + i] * var22[2 * var47 + 1] - var20[2 * var47 + 1 + i] * var22[2 * var47]; + } + + for (var47 = 0; var47 < var41; ++var47) { + var20[var4 - var41 + var47] = -var20[var47]; + } + + for (var47 = 0; var47 < var41; ++var47) { + var20[var47] = var20[var41 + var47]; + } + + for (var47 = 0; var47 < var41; ++var47) { + var20[var41 + var47] = -var20[var41 - var47 - 1]; + } + + for (var47 = 0; var47 < var41; ++var47) { + var20[i + var47] = var20[var4 - var47 - 1]; + } + + float[] var10000; + for (var47 = var8; var47 < var9; ++var47) { + var27 = (float) Math.sin(((double) (var47 - var8) + 0.5D) / (double) var10 * 0.5D * Math.PI); + var10000 = _k; + var10000[var47] *= (float) Math.sin(1.5707963267948966D * (double) var27 * (double) var27); + } + + for (var47 = var11; var47 < var12; ++var47) { + var27 = (float) Math.sin(((double) (var47 - var11) + 0.5D) / (double) var13 * 0.5D * Math.PI + (Math.PI / 2)); + var10000 = _k; + var10000[var47] *= (float) Math.sin(1.5707963267948966D * (double) var27 * (double) var27); + } + } + + float[] var43 = null; + if (this._M > 0) { + var41 = this._M + var4 >> 2; + var43 = new float[var41]; + int var45; + if (!this._A) { + for (var42 = 0; var42 < this._i; ++var42) { + var45 = (this._M >> 1) + var42; + var43[var42] += this._n[var45]; + } + } + + if (!var15) { + for (var42 = var8; var42 < var4 >> 1; ++var42) { + var45 = var43.length - (var4 >> 1) + var42; + var43[var45] += _k[var42]; + } + } + } + + final float[] var44 = this._n; + this._n = _k; + _k = var44; + this._M = var4; + this._i = var12 - (var4 >> 1); + this._A = var15; + return var43; + } + + private void a604(final byte[] var1) throws IOException { + final Buffer var2 = new Buffer(var1); + this._B = var2.readInt(); + this._q = var2.readInt(); + this._H = var2.readInt(); + this._G = var2.readInt(); + if (this._G < 0) { + this._G = ~this._G; + this._I = true; + } + + final int var3 = var2.readInt(); + if (var3 < 0) { + throw new IOException(); + } else { + this._v = new byte[var3][]; + + for (int var4 = 0; var4 < var3; ++var4) { + int var5 = 0; + + int var6; + do { + var6 = var2.readUByte(); + var5 += var6; + } while (var6 >= 255); + + final byte[] var7 = new byte[var5]; + var2.readBytes(var7, var5); + this._v[var4] = var7; + } + + } + } + + public void b720() { + this._M = 0; + this._n = new float[_r]; + for (int var3 = 0; var3 < this._v.length; ++var3) { + this.e875(var3); + } + } +} diff --git a/src/main/java/funorb/audio/fh_.java b/src/main/java/funorb/audio/fh_.java new file mode 100644 index 0000000..54ba894 --- /dev/null +++ b/src/main/java/funorb/audio/fh_.java @@ -0,0 +1,119 @@ +package funorb.audio; + +import funorb.io.Buffer; + +public final class fh_ { + public static final int[][] _e = new int[2][8]; + private static final float[][] _f = new float[2][8]; + public static int _g; + private static float _h; + public final int[] _d = new int[2]; + private final int[] _b = new int[2]; + private final int[][][] _a = new int[2][2][4]; + private final int[][][] _c = new int[2][2][4]; + + private static float a251(final float var0) { + final float var1 = 32.703197F * (float) Math.pow(2.0D, var0); + return var1 * 3.1415927F / 11025.0F; + } + + public void a086(final Buffer var1, final pn_ var2) { + final int var3 = var1.readUByte(); + this._d[0] = var3 >> 4; + this._d[1] = var3 & 15; + if (var3 == 0) { + this._b[1] = 0; + this._b[0] = 0; + } else { + this._b[0] = var1.readUShort(); + this._b[1] = var1.readUShort(); + final int var4 = var1.readUByte(); + + int var5; + int var6; + for (var5 = 0; var5 < 2; ++var5) { + for (var6 = 0; var6 < this._d[var5]; ++var6) { + this._a[var5][0][var6] = var1.readUShort(); + this._c[var5][0][var6] = var1.readUShort(); + } + } + + for (var5 = 0; var5 < 2; ++var5) { + for (var6 = 0; var6 < this._d[var5]; ++var6) { + if ((var4 & 1 << var5 * 4 << var6) == 0) { + this._a[var5][1][var6] = this._a[var5][0][var6]; + this._c[var5][1][var6] = this._c[var5][0][var6]; + } else { + this._a[var5][1][var6] = var1.readUShort(); + this._c[var5][1][var6] = var1.readUShort(); + } + } + } + + if (var4 != 0 || this._b[1] != this._b[0]) { + var2.read(var1); + } + } + } + + public int a197(final int var1, final float var2) { + float var3; + if (var1 == 0) { + var3 = (float) this._b[0] + (float) (this._b[1] - this._b[0]) * var2; + var3 *= 0.0030517578F; + _h = (float) Math.pow(0.1D, var3 / 20.0F); + _g = (int) (_h * 65536.0F); + } + + if (this._d[var1] == 0) { + return 0; + } else { + var3 = this.b427(var1, 0, var2); + _f[var1][0] = -2.0f * var3 * (float) Math.cos(this.a427(var1, 0, var2)); + _f[var1][1] = var3 * var3; + + int var4; + for (var4 = 1; var4 < this._d[var1]; ++var4) { + var3 = this.b427(var1, var4, var2); + final float var5 = -2.0f * var3 * (float) Math.cos(this.a427(var1, var4, var2)); + final float var6 = var3 * var3; + _f[var1][var4 * 2 + 1] = _f[var1][var4 * 2 - 1] * var6; + _f[var1][var4 * 2] = _f[var1][var4 * 2 - 1] * var5 + _f[var1][var4 * 2 - 2] * var6; + + for (int var7 = var4 * 2 - 1; var7 >= 2; --var7) { + final float[] var10000 = _f[var1]; + var10000[var7] += _f[var1][var7 - 1] * var5 + _f[var1][var7 - 2] * var6; + } + + final float[] var10000 = _f[var1]; + var10000[1] += _f[var1][0] * var5 + var6; + var10000[0] += var5; + } + + if (var1 == 0) { + for (var4 = 0; var4 < this._d[0] * 2; ++var4) { + final float[] var10000 = _f[0]; + var10000[var4] *= _h; + } + } + + for (var4 = 0; var4 < this._d[var1] * 2; ++var4) { + _e[var1][var4] = (int) (_f[var1][var4] * 65536.0F); + } + + return this._d[var1] * 2; + } + } + + private float a427(final int var1, final int var2, final float var3) { + float var4 = (float) this._a[var1][0][var2] + var3 * (float) (this._a[var1][1][var2] - this._a[var1][0][var2]); + var4 *= 1.2207031E-4F; + return a251(var4); + } + + private float b427(final int var1, final int var2, final float var3) { + float var4 = (float) this._c[var1][0][var2] + var3 * (float) (this._c[var1][1][var2] - this._c[var1][0][var2]); + var4 *= 0.0015258789F; + return 1.0F - (float) Math.pow(10.0D, -var4 / 20.0F); + } +} diff --git a/src/main/java/funorb/audio/fq_.java b/src/main/java/funorb/audio/fq_.java new file mode 100644 index 0000000..c4d572e --- /dev/null +++ b/src/main/java/funorb/audio/fq_.java @@ -0,0 +1,31 @@ +package funorb.audio; + +public final class fq_ { + public final int[] _b; + public final int[] _a; + public final int _c; + public int _d; + + public fq_() { + fd_.a137(16); + this._c = fd_.c784() != 0 ? fd_.a137(4) + 1 : 1; + if (fd_.c784() != 0) { + fd_.a137(8); + } + + fd_.a137(2); + if (this._c > 1) { + this._d = fd_.a137(4); + } + + this._b = new int[this._c]; + this._a = new int[this._c]; + + for (int var1 = 0; var1 < this._c; ++var1) { + fd_.a137(8); + this._b[var1] = fd_.a137(8); + this._a[var1] = fd_.a137(8); + } + + } +} diff --git a/src/main/java/funorb/audio/ga_.java b/src/main/java/funorb/audio/ga_.java new file mode 100644 index 0000000..50a7e47 --- /dev/null +++ b/src/main/java/funorb/audio/ga_.java @@ -0,0 +1,843 @@ +package funorb.audio; + +import funorb.cache.ResourceLoader; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public final class ga_ extends tn_ { + public final int[] _t = new int[16]; + public final int[] _F = new int[16]; + private final int[] _p = new int[16]; + private final int[] _y = new int[16]; + private final int[] _q = new int[16]; + private final qq_[][] _N = new qq_[16][128]; + private final int[] _r = new int[16]; + private final int[] _m = new int[16]; + private final Map _Q; + private final int[] _G = new int[16]; + private final pi_ _x = new pi_(); + private final int[] _I = new int[16]; + private final int[] _P = new int[16]; + private final int[] _E = new int[16]; + private final int[] _J = new int[16]; + private final int[] _A = new int[16]; + private final int[] _T = new int[16]; + private final rc_ _l = new rc_(this); + public final int[] _u = new int[16]; + private int volume = 256; + private final qq_[][] _K = new qq_[16][128]; + private int _M = 1000000; + private final int[] _s = new int[16]; + private int _C; + private long _O; + private int _D; + private long _n; + private boolean _v; + private MusicTrack _z; + + public ga_() { + this._Q = new HashMap<>(); + this.a679(); + this.a430(true); + } + + @SuppressWarnings("CopyConstructorMissesField") + public ga_(final ga_ var1) { + this._Q = var1._Q; + this.a679(); + this.a430(true); + } + + private static br_ a675cf(final ResourceLoader var0, final int var1) { + final byte[] var2 = var0.getSingletonResource(var1); + return var2 == null ? null : new br_(var2); + } + + public synchronized void e150() { + this.b430(true); + } + + private void b789(final int var1, final int var3) { + this._T[var1] = var3; + } + + @Override + public @NotNull Iterator iterator() { + return Collections.singletonList(this._l).iterator(); + } + + private void a326(final int var2, final int var3) { + this._E[var3] = var2; + this._u[var3] = (int) (0.5D + 2097152.0D * Math.pow(2.0D, 5.4931640625E-4D * (double) var2)); + } + + private int b237(final qq_ var1) { + int var3 = (var1._r * var1._G >> 12) + var1._J; + var3 += this._r[var1._y] * (this._T[var1._y] - 8192) >> 12; + final kc_ var4 = var1._u; + int var6; + if (var4._o > 0 && (var4._f > 0 || this._p[var1._y] > 0)) { + var6 = var4._f << 2; + final int var7 = var4._j << 1; + if (var7 > var1._C) { + var6 = var1._C * var6 / var7; + } + + var6 += this._p[var1._y] >> 7; + final double var8 = Math.sin((double) (var1._i & 511) * 0.01227184630308513D); + var3 += (int) ((double) var6 * var8); + } + + var6 = (int) ((double) (256 * var1._M._j) * Math.pow(2.0D, 3.255208333333333E-4D * (double) var3) / (double) SampledAudioChannel.SAMPLES_PER_SECOND + 0.5D); + return Math.max(var6, 1); + } + + public synchronized void f150() { + for (final br_ var2 : this._Q.values()) { + var2.e150(); + } + } + + private void a093(final int var1) { + for (final qq_ var3 : this._l._n) { + if ((var1 < 0 || var3._y == var1) && var3._E < 0) { + this._N[var3._y][var3._H] = null; + var3._E = 0; + } + } + } + + private void a172(final int var3, final int var4) { + final qq_ var5 = this._N[var3][var4]; + if (var5 != null) { + this._N[var3][var4] = null; + if ((2 & this._F[var3]) == 0) { + var5._E = 0; + } else if (this._l._n.stream().anyMatch(var6 -> var5._y == var6._y && var6._E < 0 && var6 != var5)) { + var5._E = 0; + } + } + } + + public synchronized void c430() { + this._M = 1000000; + } + + public synchronized void a679() { + for (int var4 = 0; var4 < 16; ++var4) { + this._A[var4] = 256; + } + } + + public synchronized void a350(final SoundLoader soundLoader, final ResourceLoader loader, final MusicTrack track) { + track.a797(); + + boolean var6 = true; + + for (final Map.Entry var8 : track._i.entrySet()) { + final int var9 = var8.getKey(); + br_ var10 = this._Q.get(var9); + if (var10 == null) { + var10 = a675cf(loader, var9); + if (var10 == null) { + var6 = false; + continue; + } + + this._Q.put(var9, var10); + } + + if (!var10.a972(soundLoader, var8.getValue())) { + var6 = false; + } + } + + if (var6) { + track.b797(); + } + } + + @Override + public synchronized void a150(int len) { + if (this._x.f801()) { + final int var2 = this._x._e * this._M / SampledAudioChannel.SAMPLES_PER_SECOND; + + do { + final long var3 = (long) len * (long) var2 + this._O; + if (this._n - var3 >= 0L) { + this._O = var3; + break; + } + + final int var5 = (int) ((-1L - this._O + this._n + (long) var2) / (long) var2); + this._O += (long) var5 * (long) var2; + this._l.a150(var5); + len -= var5; + this.a423(); + } while (this._x.f801()); + } + + this._l.a150(len); + } + + @SuppressWarnings("SameParameterValue") + public synchronized void setVolume(final int volume) { + this.volume = volume; + } + + private synchronized void b430(final boolean var2) { + this._x.d797(); + this._z = null; + this.a430(var2); + } + + private void b366(final int var1) { + for (final qq_ var3 : this._l._n) { + if (var1 < 0 || var1 == var3._y) { + if (var3._K != null) { + var3._K.g150(SampledAudioChannel.SAMPLES_PER_SECOND / 100); + if (var3._K.e801()) { + this._l._o.addFirst(var3._K); + } + + var3.d487(); + } + + if (var3._E < 0) { + this._N[var3._y][var3._H] = null; + } + + var3.unlink(); + } + } + } + + private void a540(final int var2) { + if ((2 & this._F[var2]) != 0) { + for (final qq_ var3 : this._l._n) { + if (var3._y == var2 && this._N[var2][var3._H] == null && var3._E < 0) { + var3._E = 0; + } + } + } + } + + public synchronized void a077(final MusicTrack var1, final boolean var3) { + this.a918(var3, var1, true); + } + + @Override + public synchronized void b397(final int[] dest, int offset, int len) { + if (this._x.f801()) { + final int var4 = this._x._e * this._M / SampledAudioChannel.SAMPLES_PER_SECOND; + + do { + final long var5 = this._O + (long) len * (long) var4; + if (this._n - var5 >= 0L) { + this._O = var5; + break; + } + + final int var7 = (int) ((-this._O + (this._n - (-((long) var4) + 1L))) / (long) var4); + this._O += (long) var7 * (long) var4; + this._l.b397(dest, offset, var7); + offset += var7; + len -= var7; + this.a423(); + } while (this._x.f801()); + } + + this._l.b397(dest, offset, len); + } + + private void a556(int var2) { + if (var2 >= 0) { + this._y[var2] = 12800; + this._G[var2] = 8192; + + this._s[var2] = 16383; + this._T[var2] = 8192; + this._p[var2] = 0; + this._J[var2] = 8192; + this.a540(var2); + this.d093(var2); + this._F[var2] = 0; + this._q[var2] = 32767; + this._r[var2] = 256; + this._t[var2] = 0; + this.a326(8192, var2); + } else { + for (var2 = 0; var2 < 16; ++var2) { + this.a556(var2); + } + } + } + + private void a430(final boolean var2) { + if (var2) { + this.b366(-1); + } else { + this.a093(-1); + } + + this.a556(-1); + + int var3; + for (var3 = 0; var3 < 16; ++var3) { + this._I[var3] = this._m[var3]; + } + + for (var3 = 0; var3 < 16; ++var3) { + this._P[var3] = this._m[var3] & -128; + } + + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public boolean a258(final qq_ var2) { + if (var2._K == null) { + if (var2._E >= 0) { + var2.unlink(); + if (var2._z > 0 && var2 == this._K[var2._y][var2._z]) { + this._K[var2._y][var2._z] = null; + } + } + + return true; + } else { + return false; + } + } + + private void a366(final int var1) { + switch (var1 & 240) { + case 128: { + this.a172(15 & var1, (32672 & var1) >> 8); + break; + } + case 144: { + final int var5a = var1 & 15; + final int var6a = var1 >> 8 & 127; + final int var7a = 127 & var1 >> 16; + if (var7a > 0) { + this.a842(var6a, var5a, var7a); + } else { + this.a172(var5a, var6a); + } + break; + } + case 160: + case 208: + break; + case 176: { + final int var5a = 15 & var1; + final int var6a = 127 & var1 >> 8; + final int var7a = 127 & var1 >> 16; + if (var6a == 0) { + this._P[var5a] = (var7a << 14) + (-2080769 & this._P[var5a]); + } + + if (var6a == 32) { + this._P[var5a] = (var7a << 7) + (-16257 & this._P[var5a]); + } + + if (var6a == 1) { + this._p[var5a] = (-16257 & this._p[var5a]) + (var7a << 7); + } + + if (var6a == 33) { + this._p[var5a] = var7a + (this._p[var5a] & -128); + } + + if (var6a == 5) { + this._J[var5a] = (-16257 & this._J[var5a]) + (var7a << 7); + } + + if (var6a == 37) { + this._J[var5a] = var7a + (this._J[var5a] & -128); + } + + if (var6a == 7) { + this._y[var5a] = (var7a << 7) + (-16257 & this._y[var5a]); + } + + if (var6a == 39) { + this._y[var5a] = (-128 & this._y[var5a]) + var7a; + } + + if (var6a == 10) { + this._G[var5a] = (var7a << 7) + (this._G[var5a] & -16257); + } + + if (var6a == 42) { + this._G[var5a] = (this._G[var5a] & -128) + var7a; + } + + if (var6a == 11) { + this._s[var5a] = (var7a << 7) + (-16257 & this._s[var5a]); + } + + if (var6a == 43) { + this._s[var5a] = var7a + (this._s[var5a] & -128); + } + + if (var6a == 64) { + if (var7a >= 64) { + this._F[var5a] = this._F[var5a] | 1; + } else { + this._F[var5a] = this._F[var5a] & -2; + } + } + + if (var6a == 65) { + if (var7a >= 64) { + this._F[var5a] = this._F[var5a] | 2; + } else { + this.a540(var5a); + this._F[var5a] = this._F[var5a] & -3; + } + } + + if (var6a == 99) { + this._q[var5a] = (var7a << 7) + (127 & this._q[var5a]); + } + + if (var6a == 98) { + this._q[var5a] = var7a + (16256 & this._q[var5a]); + } + + if (var6a == 101) { + this._q[var5a] = (this._q[var5a] & 127) + 16384 + (var7a << 7); + } + + if (var6a == 100) { + this._q[var5a] = 16384 + (this._q[var5a] & 16256) + var7a; + } + + if (var6a == 120) { + this.b366(var5a); + } + + if (var6a == 121) { + this.a556(var5a); + } + + if (var6a == 123) { + this.a093(var5a); + } + + int var8; + if (var6a == 6) { + var8 = this._q[var5a]; + if (var8 == 16384) { + this._r[var5a] = (this._r[var5a] & -16257) + (var7a << 7); + } + } + + if (var6a == 38) { + var8 = this._q[var5a]; + if (var8 == 16384) { + this._r[var5a] = var7a + (this._r[var5a] & -128); + } + } + + if (var6a == 16) { + this._t[var5a] = (var7a << 7) + (this._t[var5a] & -16257); + } + + if (var6a == 48) { + this._t[var5a] = (this._t[var5a] & -128) + var7a; + } + + if (var6a == 81) { + if (var7a >= 64) { + this._F[var5a] = this._F[var5a] | 4; + } else { + this.d093(var5a); + this._F[var5a] = this._F[var5a] & -5; + } + } + + if (var6a == 17) { + this.a326((var7a << 7) + (-16257 & this._E[var5a]), var5a); + } + + if (var6a == 49) { + this.a326((this._E[var5a] & -128) + var7a, var5a); + } + + break; + } + case 192: { + final int var5a = var1 & 15; + final int var6a = (32569 & var1) >> 8; + this.a599(var5a, this._P[var5a] + var6a); + break; + } + case 224: { + final int var5a = 15 & var1; + final int var6a = (127 & var1 >> 8) + (var1 >> 9 & 16256); + this.b789(var5a, var6a); + break; + } + default: { + if ((var1 & 255) == 255) { + this.a430(true); + } + break; + } + } + } + + @Override + public synchronized int a784() { + return 0; + } + + private synchronized void a918(final boolean var1, final MusicTrack var2, final boolean var4) { + this.b430(var4); + this._x.a604(var2._h); + this._v = var1; + this._O = 0L; + final int var5 = this._x.c784(); + + for (int var6 = 0; var5 > var6; ++var6) { + this._x.b150(var6); + this._x.d150(var6); + this._x.e150(var6); + } + + this._C = this._x.g784(); + this._D = this._x._b[this._C]; + this._n = this._x.c138(this._D); + } + + private void d093(final int var2) { + if ((4 & this._F[var2]) != 0) { + for (final qq_ var3 : this._l._n) { + if (var3._y == var2) { + var3._j = 0; + } + } + } + + } + + private void a842(final int var1, final int var2, final int var3) { + this.a172(var2, var1); + if ((this._F[var2] & 2) != 0) { + for (final Iterator it = this._l._n.descendingIterator(); it.hasNext(); ) { + final qq_ var5 = it.next(); + if (var5._y == var2 && var5._E < 0) { + this._N[var2][var5._H] = null; + this._N[var2][var1] = var5; + final int var6 = (var5._G * var5._r >> 12) + var5._J; + var5._J += -var5._H + var1 << 8; + var5._G = 4096; + var5._r = -var5._J + var6; + var5._H = var1; + return; + } + } + } + + final br_ var10 = this._Q.get(this._I[var2]); + if (var10 != null) { + final kk_ var11 = var10._h[var1]; + if (var11 != null) { + final qq_ var7 = new qq_(); + var7._y = var2; + var7._A = var10; + var7._M = var11; + var7._u = var10._j[var1]; + var7._z = var10._r[var1]; + var7._H = var1; + var7._k = var10._s[var1] * var3 * var3 * var10._q + 1024 >> 11; + var7._q = var10._t[var1] & 255; + var7._J = (var1 << 8) - (var10._k[var1] & 32767); + var7._B = 0; + var7._E = -1; + var7._F = 0; + var7._h = 0; + var7._v = 0; + if (this._t[var2] == 0) { + var7._K = al_.a771(var11, this.b237(var7), this.a510(var7), this.a237(var7)); + } else { + var7._K = al_.a771(var11, this.b237(var7), 0, this.a237(var7)); + this.a559(var7, var10._k[var1] < 0); + } + + if (var10._k[var1] < 0) { + assert var7._K != null; + var7._K.f150(); + } + + if (var7._z >= 0) { + final qq_ var9 = this._K[var2][var7._z]; + if (var9 != null && var9._E < 0) { + this._N[var2][var9._H] = null; + var9._E = 0; + } + + this._K[var2][var7._z] = var7; + } + + this._l._n.addLast(var7); + this._N[var2][var1] = var7; + } + } + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public boolean a543(final int var1, final int[] var2, final qq_ var4, final int var5) { + var4._p = SampledAudioChannel.SAMPLES_PER_SECOND / 100; + if (var4._E < 0 || var4._K != null && !var4._K.g801()) { + int var6 = var4._G; + if (var6 > 0) { + var6 -= (int) (Math.pow(2.0D, (double) this._J[var4._y] * 4.921259842519685E-4D) * 16.0D + 0.5D); + if (var6 < 0) { + var6 = 0; + } + + var4._G = var6; + } + + var4._K.d150(this.b237(var4)); + final kc_ var7 = var4._u; + var4._i += var7._o; + ++var4._C; + boolean var8 = false; + final double var9 = 5.086263020833333E-6D * (double) ((var4._H - 60 << 8) + (var4._G * var4._r >> 12)); + if (var7._h > 0) { + if (var7._a > 0) { + var4._h += (int) (Math.pow(2.0D, var9 * (double) var7._a) * 128.0D + 0.5D); + } else { + var4._h += 128; + } + + if (var7._h * var4._h >= 819200) { + var8 = true; + } + } + + if (var7._n != null) { + if (var7._k <= 0) { + var4._F += 128; + } else { + var4._F += (int) (0.5D + Math.pow(2.0D, var9 * (double) var7._k) * 128.0D); + } + + while (var4._B < var7._n.length - 2 && ('\uff00' & var7._n[2 + var4._B] << 8) < var4._F) { + var4._B += 2; + } + + if (var7._n.length - 2 == var4._B && var7._n[1 + var4._B] == 0) { + var8 = true; + } + } + + if (var4._E >= 0 && var7._e != null && (1 & this._F[var4._y]) == 0 && (var4._z < 0 || this._K[var4._y][var4._z] != var4)) { + if (var7._c <= 0) { + var4._E += 128; + } else { + var4._E += (int) (0.5D + 128.0D * Math.pow(2.0D, (double) var7._c * var9)); + } + + while (var4._v < var7._e.length - 2 && var4._E > (255 & var7._e[2 + var4._v]) << 8) { + var4._v += 2; + } + + if (var7._e.length - 2 == var4._v) { + var8 = true; + } + } + + if (var8) { + var4._K.g150(var4._p); + if (var2 == null) { + var4._K.a150(var5); + } else { + var4._K.b397(var2, var1, var5); + } + + if (var4._K.e801()) { + this._l._o.addFirst(var4._K); + } + + var4.d487(); + if (var4._E >= 0) { + var4.unlink(); + if (var4._z > 0 && this._K[var4._y][var4._z] == var4) { + this._K[var4._y][var4._z] = null; + } + } + + return true; + } else { + + var4._K.a326(var4._p, this.a510(var4), this.a237(var4)); + return false; + } + } else { + var4.d487(); + var4.unlink(); + if (var4._z > 0 && this._K[var4._y][var4._z] == var4) { + this._K[var4._y][var4._z] = null; + } + + return true; + } + } + + private void a599(final int var1, final int var2) { + if (var2 != this._I[var1]) { + this._I[var1] = var2; + for (int i = 0; i < 128; ++i) { + this._K[var1][i] = null; + } + } + } + + private int a237(final qq_ var1) { + final int var3 = this._G[var1._y]; + return var3 >= 8192 ? -(32 + (128 - var1._q) * (-var3 + 16384) >> 6) + 16384 : 32 + var1._q * var3 >> 6; + } + + private void a423() { + int var2 = this._C; + int var3 = this._D; + long var4 = this._n; + if (this._z != null && var3 == 0) { + this.a918(this._v, this._z, false); + this.a423(); + } else { + while (var3 == this._D) { + while (this._x._b[var2] == var3) { + this._x.b150(var2); + final int var7 = this._x.a137(var2); + if (var7 == 1) { + this._x.e797(); + this._x.e150(var2); + if (this._x.a801()) { + if (this._z != null) { + this.a077(this._z, this._v); + this.a423(); + return; + } + + if (!this._v || var3 == 0) { + this.a430(true); + this._x.d797(); + return; + } + + this._x.a111(var4); + } + break; + } + + if ((var7 & 128) != 0) { + this.a366(var7); + } + + this._x.d150(var2); + this._x.e150(var2); + } + + var2 = this._x.g784(); + var3 = this._x._b[var2]; + var4 = this._x.c138(var3); + } + + this._C = var2; + this._D = var3; + this._n = var4; + if (this._z != null && var3 > 0) { + this._C = -1; + this._D = 0; + this._n = this._x.c138(this._D); + } + + } + } + + public void a559(final qq_ var2, final boolean var3) { + + int var4 = var2._M.data.length; + int var5; + if (var3 && var2._M._i) { + final int var6 = -var2._M._l + var4 + var4; + var5 = (int) ((long) this._t[var2._y] * (long) var6 >> 6); + var4 <<= 8; + if (var5 >= var4) { + var2._K.c487(); + var5 = -var5 + var4 + var4 - 1; + } + } else { + var5 = (int) ((long) this._t[var2._y] * (long) var4 >> 6); + } + + var2._K.h150(var5); + } + + private int a510(final qq_ var1) { + if (this._A[var1._y] == 0) { + return 0; + } else { + final kc_ var3 = var1._u; + int var4 = this._y[var1._y] * this._s[var1._y] + 4096 >> 13; + var4 = var4 * var4 + 16384 >> 15; + var4 = var1._k * var4 + 16384 >> 15; + var4 = 128 + this.volume * var4 >> 8; + var4 = this._A[var1._y] * var4 + 128 >> 8; + if (var3._h > 0) { + var4 = (int) (0.5D + (double) var4 * Math.pow(0.5D, (double) var1._h * 1.953125E-5D * (double) var3._h)); + } + + int var5; + int var6; + int var7; + int var8; + if (var3._n != null) { + var5 = var1._F; + var6 = var3._n[1 + var1._B]; + if (var1._B < var3._n.length - 2) { + var7 = var3._n[var1._B] << 8 & '\uff00'; + var8 = (255 & var3._n[2 + var1._B]) << 8; + var6 += (-var6 + var3._n[var1._B + 3]) * (-var7 + var5) / (-var7 + var8); + } + + var4 = var6 * var4 + 32 >> 6; + } + + if (var1._E > 0 && var3._e != null) { + var5 = var1._E; + var6 = var3._e[1 + var1._v]; + if (var3._e.length - 2 > var1._v) { + var7 = (255 & var3._e[var1._v]) << 8; + var8 = var3._e[2 + var1._v] << 8 & '\uff00'; + var6 += (var3._e[var1._v + 3] - var6) * (-var7 + var5) / (-var7 + var8); + } + + var4 = 32 + var4 * var6 >> 6; + } + + return var4; + } + } + + public synchronized void initialize() { + this._m[9] = 128; + this._P[9] = 128; + this.a599(9, 128); + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public synchronized boolean h154() { + return this._x.f801(); + } +} diff --git a/src/main/java/funorb/audio/h_.java b/src/main/java/funorb/audio/h_.java new file mode 100644 index 0000000..20f172d --- /dev/null +++ b/src/main/java/funorb/audio/h_.java @@ -0,0 +1,243 @@ +package funorb.audio; + +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; + +public final class h_ extends tn_ { + public final ga_ _r; + public final ga_ _u; + private int[] _D; + private MusicTrack _E; + private int _l; + private int _n = 0x100000; + private MusicTrack _z; + private int[] _p; + private int volume = 256; + private boolean _C; + + public h_() { + final ga_ var1 = new ga_(); + this._u = var1; + this._r = new ga_(var1); + } + + public boolean a419(final MusicTrack var1) { + return var1 == this._z || var1 == this._E; + } + + @Override + public void b397(final int[] dest, final int offset, final int len) { + if (this.volume <= 0) { + this.a150(len); + } else { + if (this._C) { + if (this._l > 0 && !this._u.h154()) { + this._C = false; + this._l = -this._l; + this._z = null; + } else if (this._l < 0 && !this._r.h154()) { + this._E = null; + this._C = false; + this._l = -this._l; + } + } + + final int var4 = (this._n >> 12) * this.volume / 256; + final int var5 = this.volume - var4; + if (this._l != 0) { + this._n += this._l * len; + if (this._n >= 1048576) { + this._n = 1048576; + if (!this._C) { + this._l = 0; + if (this._E != null) { + this._r.e150(); + } + + this._E = null; + } + } else if (this._n <= 0) { + this._n = 0; + if (!this._C) { + this._l = 0; + if (this._z != null) { + this._u.e150(); + } + + this._z = null; + } + } + } + + final int var6 = len << 1; + final int var7; + int var8; + if (this._z != null || this._E != null) { + if (var4 == 256) { + this._u.b397(dest, offset, len); + } else if (var5 == 256) { + this._r.b397(dest, offset, len); + } else { + if (this._D != null && this._D.length >= var6) { + Arrays.fill(this._D, 0, var6, 0); + Arrays.fill(this._p, 0, var6, 0); + } else { + this._p = new int[var6]; + this._D = new int[var6]; + } + + this._u.b397(this._D, 0, len); + this._r.b397(this._p, 0, len); + var7 = offset << 1; + + for (var8 = 0; var6 > var8; ++var8) { + dest[var7 + var8] += this._p[var8] * var5 + this._D[var8] * var4 >> 8; + } + } + } + + } + } + + @Override + public synchronized void a150(final int len) { + if (this._n > 0 && this._z != null) { + this._u.a150(len); + } + + if (this._n < 1048576 && this._E != null) { + this._r.a150(len); + } + + if (this._C) { + if (this._l > 0 && !this._u.h154()) { + this._C = false; + this._z = null; + this._l = -this._l; + } else if (this._l < 0 && !this._r.h154()) { + this._C = false; + this._l = -this._l; + this._E = null; + } + } + + if (this._l != 0) { + this._n += this._l * len; + if (this._n >= 1048576) { + this._n = 1048576; + if (!this._C) { + this._l = 0; + if (this._E != null) { + this._r.e150(); + } + + this._E = null; + } + } else if (this._n <= 0) { + this._n = 0; + if (!this._C) { + this._l = 0; + if (this._z != null) { + this._u.e150(); + } + + this._z = null; + } + } + } + + } + + private void a633(final ga_ var3) { + var3.a679(); + var3.c430(); + } + + public synchronized void setVolume(final int volume) { + this.volume = volume; + } + + @Override + public synchronized int a784() { + return 2; + } + + @Override + public @NotNull Iterator iterator() { + return Collections.emptyIterator(); + } + + public synchronized void a180(final MusicTrack track, final int var5, final boolean var4) { + if (this._C && var4) { + if (this._l > 0) { + if (this._z != null) { + this._u.e150(); + } + + this._z = track; + if (track != null) { + this._u.a077(track, false); + this.a633(this._u); + } + } else { + if (this._E != null) { + this._r.e150(); + } + + this._E = track; + if (track != null) { + this._r.a077(track, false); + this.a633(this._r); + } + } + + } else { + this._C = var4; + if (this._z == track) { + this._l = var5; + this.a633(this._u); + } else if (track == this._E) { + this._l = -var5; + this.a633(this._r); + } else { + final boolean var7; + if (this._z == null) { + var7 = true; + } else if (this._E == null) { + var7 = false; + } else { + var7 = this._n < 524288; + } + + if (var7) { + if (this._z != null) { + this._u.e150(); + } + + this._z = track; + if (track != null) { + this._u.a077(track, !var4); + this.a633(this._u); + } + + this._l = var5; + } else { + if (this._E != null) { + this._r.e150(); + } + + this._E = track; + if (track != null) { + this._r.a077(track, !var4); + this.a633(this._r); + } + + this._l = -var5; + } + } + } + } +} diff --git a/src/main/java/funorb/audio/kc_.java b/src/main/java/funorb/audio/kc_.java new file mode 100644 index 0000000..c81a5fa --- /dev/null +++ b/src/main/java/funorb/audio/kc_.java @@ -0,0 +1,13 @@ +package funorb.audio; + +public final class kc_ { + public int _j; + public int _c; + public int _a; + public int _h; + public byte[] _e; + public int _k; + public byte[] _n; + public int _f; + public int _o; +} diff --git a/src/main/java/funorb/audio/kk_.java b/src/main/java/funorb/audio/kk_.java new file mode 100644 index 0000000..ca0ab37 --- /dev/null +++ b/src/main/java/funorb/audio/kk_.java @@ -0,0 +1,22 @@ +package funorb.audio; + +public final class kk_ { + public final int _k; + public final int _l; + public final int _j; + public final byte[] data; + public final boolean _i; + public int _h; + + public kk_(final byte[] data, final int var3, final int var4) { + this(SampledAudioChannel.SAMPLES_PER_SECOND, data, var3, var4, false); + } + + public kk_(final int var1, final byte[] data, final int var3, final int var4, final boolean var5) { + this._j = var1; + this.data = data; + this._l = var3; + this._k = var4; + this._i = var5; + } +} diff --git a/src/main/java/funorb/audio/kn_.java b/src/main/java/funorb/audio/kn_.java new file mode 100644 index 0000000..44735dd --- /dev/null +++ b/src/main/java/funorb/audio/kn_.java @@ -0,0 +1,286 @@ +package funorb.audio; + +import funorb.util.BitMath; + +public final class kn_ { + private static final float[] _j = new float[]{1.0649863E-7F, 1.1341951E-7F, 1.2079015E-7F, 1.2863978E-7F, 1.369995E-7F, 1.459025E-7F, 1.5538409E-7F, 1.6548181E-7F, 1.7623574E-7F, 1.8768856E-7F, 1.998856E-7F, 2.128753E-7F, 2.2670913E-7F, 2.4144197E-7F, 2.5713223E-7F, 2.7384212E-7F, 2.9163792E-7F, 3.1059022E-7F, 3.307741E-7F, 3.5226967E-7F, 3.7516213E-7F, 3.995423E-7F, 4.255068E-7F, 4.5315863E-7F, 4.8260745E-7F, 5.1397E-7F, 5.4737063E-7F, 5.829419E-7F, 6.208247E-7F, 6.611694E-7F, 7.041359E-7F, 7.4989464E-7F, 7.98627E-7F, 8.505263E-7F, 9.057983E-7F, 9.646621E-7F, 1.0273513E-6F, 1.0941144E-6F, 1.1652161E-6F, 1.2409384E-6F, 1.3215816E-6F, 1.4074654E-6F, 1.4989305E-6F, 1.5963394E-6F, 1.7000785E-6F, 1.8105592E-6F, 1.9282195E-6F, 2.053526E-6F, 2.1869757E-6F, 2.3290977E-6F, 2.4804558E-6F, 2.6416496E-6F, 2.813319E-6F, 2.9961443E-6F, 3.1908505E-6F, 3.39821E-6F, 3.619045E-6F, 3.8542307E-6F, 4.1047006E-6F, 4.371447E-6F, 4.6555283E-6F, 4.958071E-6F, 5.280274E-6F, 5.623416E-6F, 5.988857E-6F, 6.3780467E-6F, 6.7925284E-6F, 7.2339453E-6F, 7.704048E-6F, 8.2047E-6F, 8.737888E-6F, 9.305725E-6F, 9.910464E-6F, 1.0554501E-5F, 1.1240392E-5F, 1.1970856E-5F, 1.2748789E-5F, 1.3577278E-5F, 1.4459606E-5F, 1.5399271E-5F, 1.6400005E-5F, 1.7465769E-5F, 1.8600793E-5F, 1.9809577E-5F, 2.1096914E-5F, 2.2467912E-5F, 2.3928002E-5F, 2.5482977E-5F, 2.7139005E-5F, 2.890265E-5F, 3.078091E-5F, 3.2781227E-5F, 3.4911533E-5F, 3.718028E-5F, 3.9596467E-5F, 4.2169668E-5F, 4.491009E-5F, 4.7828602E-5F, 5.0936775E-5F, 5.424693E-5F, 5.7772202E-5F, 6.152657E-5F, 6.552491E-5F, 6.9783084E-5F, 7.4317984E-5F, 7.914758E-5F, 8.429104E-5F, 8.976875E-5F, 9.560242E-5F, 1.0181521E-4F, 1.0843174E-4F, 1.1547824E-4F, 1.2298267E-4F, 1.3097477E-4F, 1.3948625E-4F, 1.4855085E-4F, 1.5820454E-4F, 1.6848555E-4F, 1.7943469E-4F, 1.9109536E-4F, 2.0351382E-4F, 2.167393E-4F, 2.3082423E-4F, 2.4582449E-4F, 2.6179955E-4F, 2.7881275E-4F, 2.9693157E-4F, 3.1622787E-4F, 3.3677815E-4F, 3.5866388E-4F, 3.8197188E-4F, 4.0679457E-4F, 4.3323037E-4F, 4.613841E-4F, 4.913675E-4F, 5.2329927E-4F, 5.573062E-4F, 5.935231E-4F, 6.320936E-4F, 6.731706E-4F, 7.16917E-4F, 7.635063E-4F, 8.1312325E-4F, 8.6596457E-4F, 9.2223985E-4F, 9.821722E-4F, 0.0010459992F, 0.0011139743F, 0.0011863665F, 0.0012634633F, 0.0013455702F, 0.0014330129F, 0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F, 0.0019632196F, 0.0020908006F, 0.0022266726F, 0.0023713743F, 0.0025254795F, 0.0026895993F, 0.0028643848F, 0.0030505287F, 0.003248769F, 0.0034598925F, 0.0036847359F, 0.0039241905F, 0.0041792067F, 0.004450795F, 0.004740033F, 0.005048067F, 0.0053761187F, 0.005725489F, 0.0060975635F, 0.0064938175F, 0.0069158226F, 0.0073652514F, 0.007843887F, 0.008353627F, 0.008896492F, 0.009474637F, 0.010090352F, 0.01074608F, 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F, 0.014722068F, 0.015678791F, 0.016697686F, 0.017782796F, 0.018938422F, 0.020169148F, 0.021479854F, 0.022875736F, 0.02436233F, 0.025945531F, 0.027631618F, 0.029427277F, 0.031339627F, 0.03337625F, 0.035545226F, 0.037855156F, 0.0403152F, 0.042935107F, 0.045725275F, 0.048696756F, 0.05186135F, 0.05523159F, 0.05882085F, 0.062643364F, 0.06671428F, 0.07104975F, 0.075666964F, 0.08058423F, 0.08582105F, 0.09139818F, 0.097337745F, 0.1036633F, 0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F, 0.14201812F, 0.15124726F, 0.16107617F, 0.1715438F, 0.18269168F, 0.19456401F, 0.20720787F, 0.22067343F, 0.23501402F, 0.25028655F, 0.26655158F, 0.28387362F, 0.3023213F, 0.32196787F, 0.34289113F, 0.36517414F, 0.3889052F, 0.41417846F, 0.44109413F, 0.4697589F, 0.50028646F, 0.53279793F, 0.5674221F, 0.6042964F, 0.64356697F, 0.6853896F, 0.72993004F, 0.777365F, 0.8278826F, 0.88168305F, 0.9389798F, 1.0F}; + private static final int[] _a = new int[]{256, 128, 86, 64}; + private static boolean[] _g; + private static int[] _i; + private static int[] _d; + private final int[] _f; + private final int[] _c; + private final int[][] _k; + private final int[] _l; + private final int[] _h; + private final int _b; + private final int[] _e; + + public kn_() { + final int var1 = fd_.a137(16); + if (var1 == 1) { + final int var2 = fd_.a137(5); + int var3 = 0; + this._l = new int[var2]; + + int var4; + int var5; + for (var4 = 0; var4 < var2; ++var4) { + var5 = fd_.a137(4); + this._l[var4] = var5; + if (var5 >= var3) { + var3 = var5 + 1; + } + } + + this._e = new int[var3]; + this._c = new int[var3]; + this._h = new int[var3]; + this._k = new int[var3][]; + + int var7; + for (var4 = 0; var4 < var3; ++var4) { + this._e[var4] = fd_.a137(3) + 1; + var5 = this._c[var4] = fd_.a137(2); + if (var5 != 0) { + this._h[var4] = fd_.a137(8); + } + + var5 = 1 << var5; + final int[] var6 = new int[var5]; + this._k[var4] = var6; + + for (var7 = 0; var7 < var5; ++var7) { + var6[var7] = fd_.a137(8) - 1; + } + } + + this._b = fd_.a137(2) + 1; + var4 = fd_.a137(4); + var5 = 2; + + int var9; + for (var9 = 0; var9 < var2; ++var9) { + var5 += this._e[this._l[var9]]; + } + + this._f = new int[var5]; + this._f[0] = 0; + this._f[1] = 1 << var4; + var5 = 2; + + for (var9 = 0; var9 < var2; ++var9) { + var7 = this._l[var9]; + + for (int var8 = 0; var8 < this._e[var7]; ++var8) { + this._f[var5++] = fd_.a137(var4); + } + } + + if (_d == null || _d.length < var5) { + _d = new int[var5]; + _i = new int[var5]; + _g = new boolean[var5]; + } + + } else { + throw new RuntimeException(); + } + } + + private static int b691(final int[] var0, final int var1) { + final int var2 = var0[var1]; + int var3 = -1; + int var4 = Integer.MAX_VALUE; + + for (int var5 = 0; var5 < var1; ++var5) { + final int var6 = var0[var5]; + if (var6 > var2 && var6 < var4) { + var3 = var5; + var4 = var6; + } + } + + return var3; + } + + private static int a691(final int[] var0, final int var1) { + final int var2 = var0[var1]; + int var3 = -1; + int var4 = Integer.MIN_VALUE; + + for (int var5 = 0; var5 < var1; ++var5) { + final int var6 = var0[var5]; + if (var6 < var2 && var6 > var4) { + var3 = var5; + var4 = var6; + } + } + + return var3; + } + + public boolean b801() { + final boolean var1 = fd_.c784() != 0; + if (var1) { + final int var2 = this._f.length; + + int var3; + for (var3 = 0; var3 < var2; ++var3) { + _d[var3] = this._f[var3]; + } + + var3 = _a[this._b - 1]; + final int var4 = BitMath.lastSet(var3 - 1); + _i[0] = fd_.a137(var4); + _i[1] = fd_.a137(var4); + int var5 = 2; + + for (final int var7 : this._l) { + final int var8 = this._e[var7]; + final int var9 = this._c[var7]; + final int var10 = (1 << var9) - 1; + int var11 = 0; + if (var9 > 0) { + var11 = fd_._L[this._h[var7]].a784(); + } + + for (int var12 = 0; var12 < var8; ++var12) { + final int var13 = this._k[var7][var11 & var10]; + var11 >>>= var9; + _i[var5++] = var13 >= 0 ? fd_._L[var13].a784() : 0; + } + } + + return true; + } else { + return false; + } + } + + private void a093(final int var1, final int var2) { + if (var1 < var2) { + int var3 = var1; + final int var4 = _d[var1]; + final int var5 = _i[var1]; + final boolean var6 = _g[var1]; + + for (int var7 = var1 + 1; var7 <= var2; ++var7) { + final int var8 = _d[var7]; + if (var8 < var4) { + _d[var3] = var8; + _i[var3] = _i[var7]; + _g[var3] = _g[var7]; + ++var3; + _d[var7] = _d[var3]; + _i[var7] = _i[var3]; + _g[var7] = _g[var3]; + } + } + + _d[var3] = var4; + _i[var3] = var5; + _g[var3] = var6; + this.a093(var1, var3 - 1); + this.a093(var3 + 1, var2); + } + } + + private int a063(final int var1, final int var2, final int var3, final int var4, final int var5) { + final int var6 = var4 - var2; + final int var7 = var3 - var1; + final int var8 = var6 < 0 ? -var6 : var6; + final int var9 = var8 * (var5 - var1); + final int var10 = var9 / var7; + return var6 < 0 ? var2 - var10 : var2 + var10; + } + + private void a365(final int var1, final int var2, int var3, final int var4, final float[] var5, final int var6) { + final int var7 = var4 - var2; + final int var8 = var3 - var1; + int var9 = var7 < 0 ? -var7 : var7; + final int var10 = var7 / var8; + int var11 = var2; + int var12 = 0; + final int var13 = var7 < 0 ? var10 - 1 : var10 + 1; + var9 -= (var10 < 0 ? -var10 : var10) * var8; + var5[var1] *= _j[var2]; + if (var3 > var6) { + var3 = var6; + } + + for (int var14 = var1 + 1; var14 < var3; ++var14) { + var12 += var9; + if (var12 >= var8) { + var12 -= var8; + var11 += var13; + } else { + var11 += var10; + } + + var5[var14] *= _j[var11]; + } + + } + + public void a331(final float[] var1, final int var2) { + final int var3 = this._f.length; + final int var4 = _a[this._b - 1]; + final boolean[] var5 = _g; + _g[1] = true; + var5[0] = true; + + int var6; + int var7; + int var8; + int var9; + int var10; + for (var6 = 2; var6 < var3; ++var6) { + var7 = a691(_d, var6); + var8 = b691(_d, var6); + var9 = this.a063(_d[var7], _i[var7], _d[var8], _i[var8], _d[var6]); + var10 = _i[var6]; + final int var11 = var4 - var9; + final int var13 = (Math.min(var11, var9)) << 1; + if (var10 == 0) { + _g[var6] = false; + _i[var6] = var9; + } else { + final boolean[] var14 = _g; + _g[var8] = true; + var14[var7] = true; + _g[var6] = true; + if (var10 >= var13) { + _i[var6] = var11 > var9 ? var10 - var9 + var9 : var9 - var10 + var11 - 1; + } else { + _i[var6] = (var10 & 1) != 0 ? var9 - (var10 + 1) / 2 : var9 + var10 / 2; + } + } + } + + this.a093(0, var3 - 1); + var6 = 0; + var7 = _i[0] * this._b; + + for (var8 = 1; var8 < var3; ++var8) { + if (_g[var8]) { + var9 = _d[var8]; + var10 = _i[var8] * this._b; + this.a365(var6, var7, var9, var10, var1, var2); + if (var9 >= var2) { + return; + } + + var6 = var9; + var7 = var10; + } + } + + final float var16 = _j[var7]; + + for (var9 = var6; var9 < var2; ++var9) { + var1[var9] *= var16; + } + + } +} diff --git a/src/main/java/funorb/audio/pi_.java b/src/main/java/funorb/audio/pi_.java new file mode 100644 index 0000000..80cfd0b --- /dev/null +++ b/src/main/java/funorb/audio/pi_.java @@ -0,0 +1,200 @@ +package funorb.audio; + +import funorb.io.Buffer; + +import java.util.Arrays; + +public final class pi_ { + private static final byte[] _g = new byte[]{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + private final Buffer _i = new Buffer(null); + public int _e; + public int[] _b; + private int[] _h; + private int[] _c; + private int[] _d; + private long _f; + private int _a; + + public pi_() { + } + + public pi_(final byte[] var1) { + this.a604(var1); + } + + public boolean a801() { + return Arrays.stream(this._h).noneMatch(i -> i >= 0); + } + + public int a137(final int var1) { + return this.f137(var1); + } + + public void a111(final long var1) { + this._f = var1; + final int var3 = this._h.length; + + for (int var4 = 0; var4 < var3; ++var4) { + this._b[var4] = 0; + this._d[var4] = 0; + this._i.pos = this._c[var4]; + this.d150(var4); + this._h[var4] = this._i.pos; + } + + } + + public long c138(final int var1) { + return this._f + (long) var1 * (long) this._a; + } + + public void b150(final int var1) { + this._i.pos = this._h[var1]; + } + + private int a080(final int var1, final int var2) { + int var4; + if (var2 == 255) { + final int var7 = this._i.readUByte(); + var4 = this._i.readVariableInt(); + final Buffer var10000; + if (var7 == 47) { + var10000 = this._i; + var10000.pos += var4; + return 1; + } else if (var7 == 81) { + final int var5 = this._i.readU24(); + var4 -= 3; + final int var6 = this._b[var1]; + this._f += (long) var6 * (long) (this._a - var5); + this._a = var5; + var10000 = this._i; + var10000.pos += var4; + return 2; + } else { + var10000 = this._i; + var10000.pos += var4; + return 3; + } + } else { + final byte var3 = _g[var2 - 128]; + var4 = var2; + if (var3 >= 1) { + var4 = var2 | this._i.readUByte() << 8; + } + + if (var3 >= 2) { + var4 |= this._i.readUByte() << 16; + } + + return var4; + } + } + + public int g784() { + final int var1 = this._h.length; + int var2 = -1; + int var3 = Integer.MAX_VALUE; + + for (int var4 = 0; var4 < var1; ++var4) { + if (this._h[var4] >= 0 && this._b[var4] < var3) { + var2 = var4; + var3 = this._b[var4]; + } + } + + return var2; + } + + public void e797() { + this._i.pos = -1; + } + + public void e150(final int var1) { + this._h[var1] = this._i.pos; + } + + public int c784() { + return this._h.length; + } + + private int f137(final int var1) { + final byte var2 = this._i.data[this._i.pos]; + final int var5; + if (var2 < 0) { + var5 = var2 & 255; + this._d[var1] = var5; + ++this._i.pos; + } else { + var5 = this._d[var1]; + } + + if (var5 == 240 || var5 == 247) { + final int var3 = this._i.readVariableInt(); + if (var5 == 247 && var3 > 0) { + final int var4 = this._i.data[this._i.pos] & 255; + if (var4 >= 241 && var4 <= 243 || var4 == 246 || var4 == 248 || var4 >= 250 && var4 <= 252 || var4 == 254) { + ++this._i.pos; + this._d[var1] = var4; + return this.a080(var1, var4); + } + } + + this._i.pos += var3; + return 0; + } else { + return this.a080(var1, var5); + } + } + + public void d797() { + this._i.data = null; + this._c = null; + this._h = null; + this._b = null; + this._d = null; + } + + public boolean f801() { + return this._i.data != null; + } + + public void d150(final int var1) { + final int var2 = this._i.readVariableInt(); + final int[] var10000 = this._b; + var10000[var1] += var2; + } + + public void a604(final byte[] var1) { + this._i.data = var1; + this._i.pos = 10; + final int var2 = this._i.readUShort(); + this._e = this._i.readUShort(); + this._a = 500000; + this._c = new int[var2]; + + Buffer var10000; + int var3; + int var5; + for (var3 = 0; var3 < var2; var10000.pos += var5) { + final int var4 = this._i.readInt(); + var5 = this._i.readInt(); + if (var4 == 1297379947) { + this._c[var3] = this._i.pos; + ++var3; + } + + var10000 = this._i; + } + + this._f = 0L; + this._h = new int[var2]; + + for (var3 = 0; var3 < var2; ++var3) { + this._h[var3] = this._c[var3]; + } + + this._b = new int[var2]; + this._d = new int[var2]; + } +} diff --git a/src/main/java/funorb/audio/pk_.java b/src/main/java/funorb/audio/pk_.java new file mode 100644 index 0000000..d69b692 --- /dev/null +++ b/src/main/java/funorb/audio/pk_.java @@ -0,0 +1,312 @@ +package funorb.audio; + +import funorb.io.Buffer; + +import java.util.Arrays; +import java.util.Random; + +public final class pk_ { + private static final int[] NOISE = new int[0x8000]; + private static final int[] SINE = new int[0x8000]; + private static final int[] _u; + private static final int[] _p; + private static final int[] _q; + private static final int[] _t; + private static final int[] _c; + private static final int[] _w; + + static { + final Random var0 = new Random(0L); + for (int i = 0; i < 0x8000; ++i) { + NOISE[i] = (var0.nextInt() & 2) - 1; + } + for (int i = 0; i < 0x8000; ++i) { + SINE[i] = (int) (Math.sin((double) i * Math.PI / 0x4000) * 0x4000); + } + + _u = new int[220500]; + _q = new int[5]; + _t = new int[5]; + _p = new int[5]; + _w = new int[5]; + _c = new int[5]; + } + + private final int[] _y = new int[]{0, 0, 0, 0, 0}; + private final int[] _x = new int[]{0, 0, 0, 0, 0}; + private final int[] _h = new int[]{0, 0, 0, 0, 0}; + public int _s = 0; + public int _a = 500; + private fh_ _k; + private pn_ _o; + private int _f = 0; + private pn_ _r; + private pn_ _g; + private pn_ _d; + private pn_ _m; + private int _b = 100; + private pn_ _n; + private pn_ _e; + private pn_ _l; + private pn_ _i; + + public int[] a111(final int var1, final int var2) { + Arrays.fill(_u, 0, var1, 0); + if (var2 >= 10) { + final double var3 = (double) var1 / ((double) var2 + 0.0D); + this._m.reset(); + this._i.reset(); + int var5 = 0; + int var6 = 0; + int var7 = 0; + if (this._l != null) { + this._l.reset(); + this._d.reset(); + var5 = (int) ((double) (this._l._i - this._l._d) * 32.768D / var3); + var6 = (int) ((double) this._l._d * 32.768D / var3); + } + + int var8 = 0; + int var9 = 0; + int var10 = 0; + if (this._g != null) { + this._g.reset(); + this._o.reset(); + var8 = (int) ((double) (this._g._i - this._g._d) * 32.768D / var3); + var9 = (int) ((double) this._g._d * 32.768D / var3); + } + + for (int i = 0; i < 5; ++i) { + if (this._y[i] != 0) { + _c[i] = 0; + _q[i] = (int) ((double) this._h[i] * var3); + _p[i] = (this._y[i] << 14) / 100; + _t[i] = (int) ((double) (this._m._i - this._m._d) * 32.768D * Math.pow(1.0057929410678534D, this._x[i]) / var3); + _w[i] = (int) ((double) this._m._d * 32.768D / var3); + } + } + + for (int i = 0; i < var1; ++i) { + int var12 = this._m.next(var1); + int var13 = this._i.next(var1); + int var14; + int var15; + if (this._l != null) { + var14 = this._l.next(var1); + var15 = this._d.next(var1); + var12 += this.sample(this._l.sampleType, var7, var15) >> 1; + var7 += (var14 * var5 >> 16) + var6; + } + + if (this._g != null) { + var14 = this._g.next(var1); + var15 = this._o.next(var1); + var13 = var13 * ((this.sample(this._g.sampleType, var10, var15) >> 1) + 0x8000) >> 15; + var10 += (var14 * var8 >> 16) + var9; + } + + for (var14 = 0; var14 < 5; ++var14) { + if (this._y[var14] != 0) { + var15 = i + _q[var14]; + if (var15 < var1) { + _u[var15] += this.sample(this._m.sampleType, _c[var14], var13 * _p[var14] >> 15); + _c[var14] += (var12 * _t[var14] >> 16) + _w[var14]; + } + } + } + } + + if (this._e != null) { + this._e.reset(); + this._r.reset(); + int var11 = 0; + boolean var19 = true; + + for (int i = 0; i < var1; ++i) { + final int var15 = this._e.next(var1); + final int var16 = this._r.next(var1); + final int var12; + if (var19) { + var12 = this._e._d + ((this._e._i - this._e._d) * var15 >> 8); + } else { + var12 = this._e._d + ((this._e._i - this._e._d) * var16 >> 8); + } + + var11 += 256; + if (var11 >= var12) { + var11 = 0; + var19 = !var19; + } + + if (var19) { + _u[i] = 0; + } + } + } + + if (this._f > 0 && this._b > 0) { + final int var11 = (int) ((double) this._f * var3); + for (int i = var11; i < var1; ++i) { + _u[i] += _u[i - var11] * this._b / 100; + } + } + + if (this._k._d[0] > 0 || this._k._d[1] > 0) { + this._n.reset(); + int var11 = this._n.next(var1 + 1); + int var12 = this._k.a197(0, (float) var11 / 65536.0F); + int var13 = this._k.a197(1, (float) var11 / 65536.0F); + if (var1 >= var12 + var13) { + int var14 = 0; + final int var15 = Math.min(var13, var1 - var12); + + while (var14 < var15) { + int var16 = (int) ((long) _u[var14 + var12] * (long) fh_._g >> 16); + + for (int var17 = 0; var17 < var12; ++var17) { + var16 += (int) ((long) _u[var14 + var12 - 1 - var17] * (long) fh_._e[0][var17] >> 16); + } + + for (int var17 = 0; var17 < var14; ++var17) { + var16 -= (int) ((long) _u[var14 - 1 - var17] * (long) fh_._e[1][var17] >> 16); + } + + _u[var14] = var16; + var11 = this._n.next(var1 + 1); + ++var14; + } + + int var15a = 128; + while (true) { + if (var15a > var1 - var12) { + var15a = var1 - var12; + } + + while (var14 < var15a) { + int var16 = (int) ((long) _u[var14 + var12] * (long) fh_._g >> 16); + + for (int var17 = 0; var17 < var12; ++var17) { + var16 += (int) ((long) _u[var14 + var12 - 1 - var17] * (long) fh_._e[0][var17] >> 16); + } + + for (int var17 = 0; var17 < var13; ++var17) { + var16 -= (int) ((long) _u[var14 - 1 - var17] * (long) fh_._e[1][var17] >> 16); + } + + _u[var14] = var16; + var11 = this._n.next(var1 + 1); + ++var14; + } + + if (var14 >= var1 - var12) { + while (var14 < var1) { + int var16 = 0; + + for (int var17 = var14 + var12 - var1; var17 < var12; ++var17) { + var16 += (int) ((long) _u[var14 + var12 - 1 - var17] * (long) fh_._e[0][var17] >> 16); + } + + for (int var17 = 0; var17 < var13; ++var17) { + var16 -= (int) ((long) _u[var14 - 1 - var17] * (long) fh_._e[1][var17] >> 16); + } + + _u[var14] = var16; + this._n.next(var1 + 1); + ++var14; + } + break; + } + + var12 = this._k.a197(0, (float) var11 / 65536.0F); + var13 = this._k.a197(1, (float) var11 / 65536.0F); + var15a += 128; + } + } + } + + for (int i = 0; i < var1; ++i) { + if (_u[i] < 0xffff8000) { + _u[i] = 0xffff8000; + } + if (_u[i] > 0x7fff) { + _u[i] = 0x7fff; + } + } + } + return _u; + } + + public void initialize(final Buffer buffer) { + this._m = new pn_(); + this._m.initialize(buffer); + this._i = new pn_(); + this._i.initialize(buffer); + final int var2 = buffer.readUByte(); + if (var2 != 0) { + --buffer.pos; + this._l = new pn_(); + this._l.initialize(buffer); + this._d = new pn_(); + this._d.initialize(buffer); + } + + final int var2a = buffer.readUByte(); + if (var2a != 0) { + --buffer.pos; + this._g = new pn_(); + this._g.initialize(buffer); + this._o = new pn_(); + this._o.initialize(buffer); + } + + final int j137 = buffer.readUByte(); + if (j137 != 0) { + --buffer.pos; + this._e = new pn_(); + this._e.initialize(buffer); + this._r = new pn_(); + this._r.initialize(buffer); + } + + for (int i = 0; i < 10; ++i) { + final int var4 = buffer.readVariable8_16(); + if (var4 == 0) { + break; + } + + this._y[i] = var4; + this._x[i] = buffer.d410(); + this._h[i] = buffer.readVariable8_16(); + } + + this._f = buffer.readVariable8_16(); + this._b = buffer.readVariable8_16(); + this._a = buffer.readUShort(); + this._s = buffer.readUShort(); + this._k = new fh_(); + this._n = new pn_(); + this._k.a086(buffer, this._n); + } + + private int sample(final int type, final int time, final int volume) { + if (type == SampleType.SQUARE) { + return ((time & 0x7fff) < 0x4000) ? volume : -volume; + } else if (type == SampleType.SINE) { + return (SINE[time & 0x7fff] * volume) >> 14; + } else if (type == SampleType.SAWTOOTH) { + return (((time & 0x7fff) * volume) >> 14) - volume; + } else if (type == SampleType.NOISE) { + return NOISE[(time / 2607) & 0x7fff] * volume; + } else { + return 0; + } + } + + @SuppressWarnings("WeakerAccess") + private static final class SampleType { + public static final int SQUARE = 1; + public static final int SINE = 2; + public static final int SAWTOOTH = 3; + public static final int NOISE = 4; + } +} diff --git a/src/main/java/funorb/audio/pn_.java b/src/main/java/funorb/audio/pn_.java new file mode 100644 index 0000000..3212aad --- /dev/null +++ b/src/main/java/funorb/audio/pn_.java @@ -0,0 +1,65 @@ +package funorb.audio; + +import funorb.io.Buffer; + +public final class pn_ { + public int _d; + public int _i; + public int sampleType; + private int count = 2; + private int[] values1 = new int[2]; + private int[] values2 = new int[2]; + private int _g; + private int _e; + private int _b; + private int _j; + private int pos; + + public pn_() { + this.values1[1] = 65535; + this.values2[1] = 65535; + } + + public void initialize(final Buffer buffer) { + this.sampleType = buffer.readUByte(); + this._d = buffer.readInt(); + this._i = buffer.readInt(); + this.read(buffer); + } + + public void read(final Buffer buffer) { + this.count = buffer.readUByte(); + this.values1 = new int[this.count]; + this.values2 = new int[this.count]; + for (int i = 0; i < this.count; ++i) { + this.values1[i] = buffer.readUShort(); + this.values2[i] = buffer.readUShort(); + } + } + + public void reset() { + this._e = 0; + this.pos = 0; + this._b = 0; + this._j = 0; + this._g = 0; + } + + public int next(final int var1) { + if (this._g >= this._e) { + this._j = this.values2[this.pos++] << 15; + if (this.pos >= this.count) { + this.pos = this.count - 1; + } + + this._e = (int) (((double) this.values1[this.pos] / 65536.0D) * (double) var1); + if (this._e > this._g) { + this._b = ((this.values2[this.pos] << 15) - this._j) / (this._e - this._g); + } + } + + this._j += this._b; + ++this._g; + return this._j - this._b >> 15; + } +} diff --git a/src/main/java/funorb/audio/qq_.java b/src/main/java/funorb/audio/qq_.java new file mode 100644 index 0000000..8b7b2af --- /dev/null +++ b/src/main/java/funorb/audio/qq_.java @@ -0,0 +1,34 @@ +package funorb.audio; + +import funorb.data.NodeList; + +public final class qq_ extends NodeList.Node { + public int _E; + public int _G; + public int _v; + public int _F; + public int _H; + public kk_ _M; + public kc_ _u; + public al_ _K; + public br_ _A; + public int _j; + public int _r; + public int _C; + public int _q; + public int _y; + public int _J; + public int _h; + public int _z; + public int _k; + public int _p; + public int _B; + public int _i; + + public void d487() { + this._A = null; + this._K = null; + this._M = null; + this._u = null; + } +} diff --git a/src/main/java/funorb/audio/rc_.java b/src/main/java/funorb/audio/rc_.java new file mode 100644 index 0000000..8ca470e --- /dev/null +++ b/src/main/java/funorb/audio/rc_.java @@ -0,0 +1,147 @@ +package funorb.audio; + +import funorb.data.NodeList; +import org.jetbrains.annotations.NotNull; + +import java.util.Iterator; +import java.util.Objects; + +public final class rc_ extends tn_ { + public final NodeList _n = new NodeList<>(); + public final vk_ _o = new vk_(); + private final ga_ _m; + + public rc_(final ga_ var1) { + this._m = var1; + } + + @Override + public @NotNull Iterator iterator() { + return this._n.stream().map(var1 -> var1._K).filter(Objects::nonNull).iterator(); + } + + @Override + public int a784() { + return 0; + } + + @Override + public void a150(final int len) { + this._o.a150(len); + + for (final qq_ var3 : this._n) { + if (!this._m.a258(var3)) { + int var2 = len; + + do { + if (var3._p >= var2) { + this.a222(var3, var2); + var3._p -= var2; + break; + } + + this.a222(var3, var3._p); + var2 -= var3._p; + } while (!this._m.a543(0, null, var3, var2)); + } + } + + } + + @Override + public void b397(final int[] dest, final int offset, final int len) { + this._o.b397(dest, offset, len); + + for (final qq_ var6 : this._n) { + if (!this._m.a258(var6)) { + int var4 = offset; + int var5 = len; + + do { + if (var6._p >= var5) { + this.a829(dest, var4, var6, var5, var4 + var5); + var6._p -= var5; + break; + } + + this.a829(dest, var4, var6, var6._p, var4 + var5); + var5 -= var6._p; + var4 += var6._p; + } while (!this._m.a543(var4, dest, var6, var5)); + } + } + + } + + private void a222(final qq_ var2, int var3) { + if ((4 & this._m._F[var2._y]) != 0 && var2._E < 0) { + final int var4 = this._m._u[var2._y] / SampledAudioChannel.SAMPLES_PER_SECOND; + final int var5 = (1048575 + var4 - var2._j) / var4; + var2._j = 1048575 & var2._j + var3 * var4; + if (var5 <= var3) { + if (this._m._t[var2._y] == 0) { + var2._K = al_.a771(var2._M, var2._K.f784(), var2._K.getVolume(), var2._K.l784()); + } else { + var2._K = al_.a771(var2._M, var2._K.f784(), 0, var2._K.l784()); + this._m.a559(var2, var2._A._k[var2._H] < 0); + } + + if (var2._A._k[var2._H] < 0) { + assert var2._K != null; + var2._K.f150(); + } + + var3 = var2._j / var4; + } + } + + assert var2._K != null; + var2._K.a150(var3); + } + + private void a829(final int[] var1, int var2, final qq_ var3, int var4, final int var6) { + if ((4 & this._m._F[var3._y]) != 0 && var3._E < 0) { + final int var7 = this._m._u[var3._y] / SampledAudioChannel.SAMPLES_PER_SECOND; + + while (true) { + final int var8 = (-var3._j + 1048575 + var7) / var7; + if (var8 > var4) { + var3._j += var7 * var4; + break; + } + + var3._K.b397(var1, var2, var8); + var3._j += var8 * var7 - 1048576; + var2 += var8; + var4 -= var8; + int var9 = SampledAudioChannel.SAMPLES_PER_SECOND / 100; + final int var10 = 262144 / var7; + if (var10 < var9) { + var9 = var10; + } + + final al_ var11 = var3._K; + if (this._m._t[var3._y] == 0) { + var3._K = al_.a771(var3._M, var11.f784(), var11.getVolume(), var11.l784()); + } else { + var3._K = al_.a771(var3._M, var11.f784(), 0, var11.l784()); + this._m.a559(var3, var3._A._k[var3._H] < 0); + var3._K.a093(var9, var11.getVolume()); + } + + if (var3._A._k[var3._H] < 0) { + assert var3._K != null; + var3._K.f150(); + } + + var11.g150(var9); + var11.b397(var1, var2, var6 - var2); + if (var11.e801()) { + this._o.addFirst(var11); + } + } + } + + var3._K.b397(var1, var2, var4); + } +} diff --git a/src/main/java/funorb/audio/tn_.java b/src/main/java/funorb/audio/tn_.java new file mode 100644 index 0000000..3b98e52 --- /dev/null +++ b/src/main/java/funorb/audio/tn_.java @@ -0,0 +1,30 @@ +package funorb.audio; + +import funorb.data.NodeList; + +public abstract class tn_ extends NodeList.Node implements Iterable { + public volatile boolean _j = true; + public int _i; + public tn_ _h; + public kk_ _k; + + protected tn_() {} + + public abstract void b397(int[] dest, int offset, int len); + + protected final void a397(final int[] dest, final int offset, final int len) { + if (this._j) { + this.b397(dest, offset, len); + } else { + this.a150(len); + } + } + + public abstract void a150(int len); + + public abstract int a784(); + + public int c784() { + return 255; + } +} diff --git a/src/main/java/funorb/audio/to_.java b/src/main/java/funorb/audio/to_.java new file mode 100644 index 0000000..1629f93 --- /dev/null +++ b/src/main/java/funorb/audio/to_.java @@ -0,0 +1,106 @@ +package funorb.audio; + +public final class to_ { + private final int[] _e; + private final int _c = fd_.a137(16); + private final int _g = fd_.a137(24); + private final int _d = fd_.a137(24); + private final int _b = fd_.a137(24) + 1; + private final int _a = fd_.a137(6) + 1; + private final int _f = fd_.a137(8); + + public to_() { + final int[] var1 = new int[this._a]; + + int var2; + for (var2 = 0; var2 < this._a; ++var2) { + int var3 = 0; + final int var4 = fd_.a137(3); + final boolean var5 = fd_.c784() != 0; + if (var5) { + var3 = fd_.a137(5); + } + + var1[var2] = var3 << 3 | var4; + } + + this._e = new int[this._a * 8]; + + for (var2 = 0; var2 < this._a * 8; ++var2) { + this._e[var2] = (var1[var2 >> 3] & 1 << (var2 & 7)) != 0 ? fd_.a137(8) : -1; + } + + } + + public void a623(final float[] var1, final int var2, final boolean var3) { + int var4; + for (var4 = 0; var4 < var2; ++var4) { + var1[var4] = 0.0F; + } + + if (!var3) { + var4 = fd_._L[this._f]._a; + final int var5 = this._d - this._g; + final int var6 = var5 / this._b; + final int[] var7 = new int[var6]; + + for (int var8 = 0; var8 < 8; ++var8) { + int var9 = 0; + + while (var9 < var6) { + int var10; + int var11; + if (var8 == 0) { + var10 = fd_._L[this._f].a784(); + + for (var11 = var4 - 1; var11 >= 0; --var11) { + if (var9 + var11 < var6) { + var7[var9 + var11] = var10 % this._a; + } + + var10 /= this._a; + } + } + + for (var10 = 0; var10 < var4; ++var10) { + var11 = var7[var9]; + final int var12 = this._e[var11 * 8 + var8]; + if (var12 >= 0) { + final int var13 = this._g + var9 * this._b; + final vb_ var14 = fd_._L[var12]; + int var15; + if (this._c == 0) { + var15 = this._b / var14._a; + + for (int var19 = 0; var19 < var15; ++var19) { + final float[] var20 = var14.c932(); + + for (int var18 = 0; var18 < var14._a; ++var18) { + var1[var13 + var19 + var18 * var15] += var20[var18]; + } + } + } else { + var15 = 0; + + while (var15 < this._b) { + final float[] var16 = var14.c932(); + + for (int var17 = 0; var17 < var14._a; ++var17) { + var1[var13 + var15] += var16[var17]; + ++var15; + } + } + } + } + + ++var9; + if (var9 >= var6) { + break; + } + } + } + } + + } + } +} diff --git a/src/main/java/funorb/audio/vb_.java b/src/main/java/funorb/audio/vb_.java new file mode 100644 index 0000000..4743845 --- /dev/null +++ b/src/main/java/funorb/audio/vb_.java @@ -0,0 +1,232 @@ +package funorb.audio; + +import funorb.util.BitMath; + +public final class vb_ { + public final int _a; + private final int _c; + private final int[] _b; + private float[][] _d; + private int[] _f; + + public vb_() { + fd_.a137(24); + this._a = fd_.a137(16); + this._c = fd_.a137(24); + this._b = new int[this._c]; + final boolean var1 = fd_.c784() != 0; + int var2; + int var3; + int var5; + if (var1) { + var2 = 0; + + for (var3 = fd_.a137(5) + 1; var2 < this._c; ++var3) { + final int var4 = fd_.a137(BitMath.lastSet(this._c - var2)); + + for (var5 = 0; var5 < var4; ++var5) { + this._b[var2++] = var3; + } + } + } else { + final boolean var14 = fd_.c784() != 0; + + for (var3 = 0; var3 < this._c; ++var3) { + if (var14 && fd_.c784() == 0) { + this._b[var3] = 0; + } else { + this._b[var3] = fd_.a137(5) + 1; + } + } + } + + this.b797(); + var2 = fd_.a137(4); + if (var2 > 0) { + final float var15 = fd_.d134(fd_.a137(32)); + final float var16 = fd_.d134(fd_.a137(32)); + var5 = fd_.a137(4) + 1; + final boolean var6 = fd_.c784() != 0; + final int var7; + if (var2 == 1) { + var7 = a080(this._c, this._a); + } else { + var7 = this._c * this._a; + } + + final int[] _e = new int[var7]; + + int var8; + for (var8 = 0; var8 < var7; ++var8) { + _e[var8] = fd_.a137(var5); + } + + this._d = new float[this._c][this._a]; + float var9; + int var10; + int var11; + if (var2 == 1) { + for (var8 = 0; var8 < this._c; ++var8) { + var9 = 0.0F; + var10 = 1; + + for (var11 = 0; var11 < this._a; ++var11) { + final int var12 = var8 / var10 % var7; + final float var13 = (float) _e[var12] * var16 + var15 + var9; + this._d[var8][var11] = var13; + if (var6) { + var9 = var13; + } + + var10 *= var7; + } + } + } else { + for (var8 = 0; var8 < this._c; ++var8) { + var9 = 0.0F; + var10 = var8 * this._a; + + for (var11 = 0; var11 < this._a; ++var11) { + final float var17 = (float) _e[var10] * var16 + var15 + var9; + this._d[var8][var11] = var17; + if (var6) { + var9 = var17; + } + + ++var10; + } + } + } + } + + } + + private static int a080(final int var0, final int var1) { + int var2 = (int) Math.pow(var0, 1.0D / (double) var1) + 1; + while (a776em(var2, var1) > var0) { + --var2; + } + return var2; + } + + private static int a776em(int var0, int var1) { + int var2; + for (var2 = 1; var1 > 1; var0 *= var0) { + if ((var1 & 1) != 0) { + var2 *= var0; + } + + var1 >>= 1; + } + + if (var1 == 1) { + return var2 * var0; + } else { + return var2; + } + } + + public float[] c932() { + return this._d[this.a784()]; + } + + public int a784() { + int var1 = 0; + while (this._f[var1] >= 0) { + var1 = fd_.c784() != 0 ? this._f[var1] : var1 + 1; + } + return ~this._f[var1]; + } + + private void b797() { + final int[] var1 = new int[this._c]; + final int[] var2 = new int[33]; + + int var3; + int var4; + int var5; + int var6; + int var7; + int var8; + int var10; + for (var3 = 0; var3 < this._c; ++var3) { + var4 = this._b[var3]; + if (var4 != 0) { + var5 = 1 << 32 - var4; + var6 = var2[var4]; + var1[var3] = var6; + int var9; + if ((var6 & var5) == 0) { + var7 = var6 | var5; + + for (var8 = var4 - 1; var8 >= 1; --var8) { + var9 = var2[var8]; + if (var9 != var6) { + break; + } + + var10 = 1 << 32 - var8; + if ((var9 & var10) != 0) { + var2[var8] = var2[var8 - 1]; + break; + } + + var2[var8] = var9 | var10; + } + } else { + var7 = var2[var4 - 1]; + } + + var2[var4] = var7; + + for (var8 = var4 + 1; var8 <= 32; ++var8) { + var9 = var2[var8]; + if (var9 == var6) { + var2[var8] = var7; + } + } + } + } + + this._f = new int[8]; + int var11 = 0; + + for (var3 = 0; var3 < this._c; ++var3) { + var4 = this._b[var3]; + if (var4 != 0) { + var5 = var1[var3]; + var6 = 0; + + for (var7 = 0; var7 < var4; ++var7) { + var8 = Integer.MIN_VALUE >>> var7; + if ((var5 & var8) == 0) { + ++var6; + } else { + if (this._f[var6] == 0) { + this._f[var6] = var11; + } + + var6 = this._f[var6]; + } + + if (var6 >= this._f.length) { + final int[] var12 = new int[this._f.length * 2]; + + for (var10 = 0; var10 < this._f.length; ++var10) { + var12[var10] = this._f[var10]; + } + + this._f = var12; + } + + } + + this._f[var6] = ~var3; + if (var6 >= var11) { + var11 = var6 + 1; + } + } + } + + } +} diff --git a/src/main/java/funorb/audio/vk_.java b/src/main/java/funorb/audio/vk_.java new file mode 100644 index 0000000..2f1b1c9 --- /dev/null +++ b/src/main/java/funorb/audio/vk_.java @@ -0,0 +1,38 @@ +package funorb.audio; + +import funorb.data.NodeList; +import org.jetbrains.annotations.NotNull; + +import java.util.Iterator; + +public final class vk_ extends tn_ { + private final NodeList _l = new NodeList<>(); + + @Override + public @NotNull Iterator iterator() { + return this._l.iterator(); + } + + @Override + public int a784() { + return 0; + } + + @Override + public synchronized void a150(final int len) { + for (final tn_ var2 : this._l) { + var2.a150(len); + } + } + + public synchronized void addFirst(final al_ var1) { + this._l.addFirst(var1); + } + + @Override + public synchronized void b397(final int[] dest, final int offset, final int len) { + for (final tn_ var4 : this._l) { + var4.a397(dest, offset, len); + } + } +} diff --git a/src/main/java/funorb/awt/CanvasScreenBuffer.java b/src/main/java/funorb/awt/CanvasScreenBuffer.java new file mode 100644 index 0000000..8426c89 --- /dev/null +++ b/src/main/java/funorb/awt/CanvasScreenBuffer.java @@ -0,0 +1,35 @@ +package funorb.awt; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.awt.image.DirectColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.util.Hashtable; + +public final class CanvasScreenBuffer extends ScreenBuffer { + private Component canvas; + + public CanvasScreenBuffer() { + } + + @Override + public void paint(final Graphics g) { + g.drawImage(this.screenBufferImage, 0, 0, this.canvas); + } + + @Override + public void initialize(final Component canvas, final int width, final int height) { + this.canvas = canvas; + this.width = width; + this.height = height; + this.screenBuffer = new int[width * height + 1]; + final DataBufferInt dataBuffer = new DataBufferInt(this.screenBuffer, this.screenBuffer.length); + final DirectColorModel colorModel = new DirectColorModel(32, 0xff0000, 0x00ff00, 0x0000ff); + final WritableRaster raster = Raster.createWritableRaster(colorModel.createCompatibleSampleModel(super.width, super.height), dataBuffer, null); + this.screenBufferImage = new BufferedImage(colorModel, raster, false, new Hashtable<>()); + this.makeGlobal(); + } +} diff --git a/src/main/java/funorb/awt/ComponentCanvas.java b/src/main/java/funorb/awt/ComponentCanvas.java new file mode 100644 index 0000000..77a0532 --- /dev/null +++ b/src/main/java/funorb/awt/ComponentCanvas.java @@ -0,0 +1,23 @@ +package funorb.awt; + +import java.awt.Canvas; +import java.awt.Component; +import java.awt.Graphics; + +public final class ComponentCanvas extends Canvas { + private final Component component; + + public ComponentCanvas(final Component component) { + this.component = component; + } + + @Override + public void paint(final Graphics g) { + this.component.paint(g); + } + + @Override + public void update(final Graphics g) { + this.component.update(g); + } +} diff --git a/src/main/java/funorb/awt/FullScreenCanvas.java b/src/main/java/funorb/awt/FullScreenCanvas.java new file mode 100644 index 0000000..6856a34 --- /dev/null +++ b/src/main/java/funorb/awt/FullScreenCanvas.java @@ -0,0 +1,35 @@ +package funorb.awt; + +import funorb.shatteredplans.client.JagexApplet; + +import java.awt.Canvas; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; + +public final class FullScreenCanvas extends Canvas implements FocusListener { + public Frame frame; + public volatile boolean focusWasLost; + + @Override + public void update(final Graphics var1) { + } + + @Override + public void paint(final Graphics var1) { + } + + public void repeatedlyTryToExitFullScreen() { + JagexApplet.repeatedlyTryToExitFullScreen(this.frame); + } + + @Override + public void focusLost(final FocusEvent var1) { + this.focusWasLost = true; + } + + @Override + public void focusGained(final FocusEvent var1) { + } +} diff --git a/src/main/java/funorb/awt/GraphicsBackend.java b/src/main/java/funorb/awt/GraphicsBackend.java new file mode 100644 index 0000000..bc60525 --- /dev/null +++ b/src/main/java/funorb/awt/GraphicsBackend.java @@ -0,0 +1,87 @@ +package funorb.awt; + +import java.awt.DisplayMode; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; + +public final class GraphicsBackend { + private GraphicsDevice device; + private DisplayMode mode; + + public GraphicsBackend() throws Exception { + final GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment(); + this.device = environment.getDefaultScreenDevice(); + if (!this.device.isFullScreenSupported()) { + final GraphicsDevice[] devices = environment.getScreenDevices(); + for (final GraphicsDevice device : devices) { + if (device != null && device.isFullScreenSupported()) { + this.device = device; + return; + } + } + + throw new Exception(); + } + } + + public int[] listmodes() { + final DisplayMode[] modes = this.device.getDisplayModes(); + final int[] values = new int[modes.length << 2]; + + for (int i = 0; i < modes.length; ++i) { + values[i << 2] = modes[i].getWidth(); + values[(i << 2) + 1] = modes[i].getHeight(); + values[(i << 2) + 2] = modes[i].getBitDepth(); + values[(i << 2) + 3] = modes[i].getRefreshRate(); + } + + return values; + } + + public void enter(final Frame var1, final int var2, final int var3, final int var4, int var5) { + this.mode = this.device.getDisplayMode(); + if (this.mode == null) { + throw new NullPointerException(); + } else { + var1.setUndecorated(true); + var1.enableInputMethods(false); + + this.device.setFullScreenWindow(var1); + if (var5 == 0) { + final int var6 = this.mode.getRefreshRate(); + final DisplayMode[] var7 = this.device.getDisplayModes(); + boolean var8 = false; + + for (final DisplayMode displayMode : var7) { + if (var2 == displayMode.getWidth() && var3 == displayMode.getHeight() && displayMode.getBitDepth() == var4) { + final int var10 = displayMode.getRefreshRate(); + if (!var8 || Math.abs(-var6 + var10) < Math.abs(-var6)) { + var8 = true; + var5 = var10; + } + } + } + + if (!var8) { + var5 = var6; + } + } + + this.device.setDisplayMode(new DisplayMode(var2, var3, var4, var5)); + } + } + + public void exit() { + if (this.mode != null) { + this.device.setDisplayMode(this.mode); + if (!this.device.getDisplayMode().equals(this.mode)) { + throw new RuntimeException(""); + } + + this.mode = null; + } + + this.device.setFullScreenWindow(null); + } +} diff --git a/src/main/java/funorb/awt/ImageProducerScreenBuffer.java b/src/main/java/funorb/awt/ImageProducerScreenBuffer.java new file mode 100644 index 0000000..31dcc6d --- /dev/null +++ b/src/main/java/funorb/awt/ImageProducerScreenBuffer.java @@ -0,0 +1,79 @@ +package funorb.awt; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; + +public final class ImageProducerScreenBuffer extends ScreenBuffer implements ImageProducer, ImageObserver { + private ImageConsumer consumer; + private ColorModel colorModel; + + @Override + public void requestTopDownLeftRightResend(final ImageConsumer consumer) { + } + + @Override + public synchronized boolean isConsumer(final ImageConsumer consumer) { + return consumer == this.consumer; + } + + @Override + public boolean imageUpdate(final Image var1, final int var2, final int var3, final int var4, final int var5, final int var6) { + return true; + } + + private synchronized void pushFrame() { + if (this.consumer != null) { + this.consumer.setPixels(0, 0, this.width, this.height, this.colorModel, this.screenBuffer, 0, this.width); + this.consumer.imageComplete(ImageConsumer.SINGLEFRAMEDONE); + } + } + + @Override + public void initialize(final Component canvas, final int width, final int height) { + this.height = height; + this.width = width; + this.screenBuffer = new int[height * width + 1]; + this.colorModel = new DirectColorModel(32, 16711680, 65280, 255); + this.screenBufferImage = canvas.createImage(this); + this.pushFrame(); + canvas.prepareImage(this.screenBufferImage, this); + this.pushFrame(); + canvas.prepareImage(this.screenBufferImage, this); + this.pushFrame(); + canvas.prepareImage(this.screenBufferImage, this); + this.makeGlobal(); + } + + @Override + public synchronized void removeConsumer(final ImageConsumer consumer) { + if (consumer == this.consumer) { + this.consumer = null; + } + } + + @Override + public void startProduction(final ImageConsumer consumer) { + this.addConsumer(consumer); + } + + @Override + public synchronized void addConsumer(final ImageConsumer consumer) { + this.consumer = consumer; + consumer.setDimensions(this.width, this.height); + consumer.setProperties(null); + consumer.setColorModel(this.colorModel); + consumer.setHints(14); + } + + @Override + public void paint(final Graphics g) { + this.pushFrame(); + g.drawImage(this.screenBufferImage, 0, 0, this); + } +} diff --git a/src/main/java/funorb/awt/KeyState.java b/src/main/java/funorb/awt/KeyState.java new file mode 100644 index 0000000..b89408b --- /dev/null +++ b/src/main/java/funorb/awt/KeyState.java @@ -0,0 +1,326 @@ +package funorb.awt; + +import funorb.Strings; + +import java.awt.Component; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.util.Arrays; + +import static java.awt.event.InputEvent.ALT_MASK; +import static java.awt.event.InputEvent.CTRL_MASK; + +public final class KeyState implements KeyListener, FocusListener { + public static final KeyState instance = new KeyState(); + + @SuppressWarnings("WeakerAccess") + public static final class Code { + public static final int F1 = 1; + public static final int F2 = 2; + public static final int F3 = 3; + public static final int F4 = 4; + public static final int F5 = 5; + public static final int F6 = 6; + public static final int F7 = 7; + public static final int F8 = 8; + public static final int F9 = 9; + public static final int F10 = 10; + public static final int F11 = 11; + public static final int F12 = 12; + public static final int ESCAPE = 13; + public static final int NUMBER_1 = 16; + public static final int NUMBER_2 = 17; + public static final int NUMBER_3 = 18; + public static final int NUMBER_4 = 19; + public static final int NUMBER_5 = 20; + public static final int NUMBER_6 = 21; + public static final int NUMBER_7 = 22; + public static final int NUMBER_8 = 23; + public static final int NUMBER_9 = 24; + public static final int NUMBER_0 = 25; + public static final int LETTER_Q = 32; + public static final int LETTER_W = 33; + public static final int LETTER_E = 34; + public static final int LETTER_R = 35; + public static final int LETTER_T = 36; + public static final int LETTER_Y = 37; + public static final int LETTER_U = 38; + public static final int LETTER_I = 39; + public static final int LETTER_O = 40; + public static final int LETTER_P = 41; + public static final int LETTER_A = 48; + public static final int LETTER_S = 49; + public static final int LETTER_D = 50; + public static final int LETTER_F = 51; + public static final int LETTER_G = 52; + public static final int LETTER_H = 53; + public static final int LETTER_B = 68; + public static final int LETTER_J = 54; + public static final int LETTER_K = 55; + public static final int LETTER_L = 56; + public static final int LETTER_Z = 64; + public static final int LETTER_X = 65; + public static final int LETTER_C = 66; + public static final int LETTER_V = 67; + public static final int LETTER_N = 69; + public static final int LETTER_M = 70; + public static final int FORWARD_SLASH = 73; + public static final int TAB = 80; + public static final int SHIFT = 81; + public static final int CONTROL = 82; + public static final int SPACE = 83; + public static final int ENTER = 84; + public static final int BACKSPACE = 85; + public static final int ALT = 86; + public static final int CLEAR = 91; + public static final int LEFT = 96; + public static final int RIGHT = 97; + public static final int UP = 98; + public static final int DOWN = 99; + public static final int INSERT = 100; + public static final int DELETE = 101; + public static final int HOME = 102; + public static final int END = 103; + public static final int PAGE_UP = 104; + public static final int PAGE_DOWN = 105; + } + + private static final int[] codeMapping = new int[521]; + + static { + Arrays.fill(codeMapping, -1); + codeMapping[ 8] = Code.BACKSPACE; + codeMapping[ 9] = Code.TAB; + codeMapping[ 10] = Code.ENTER; + codeMapping[ 12] = Code.CLEAR; + codeMapping[ 16] = Code.SHIFT; + codeMapping[ 17] = Code.CONTROL; + codeMapping[ 18] = Code.ALT; + codeMapping[ 27] = Code.ESCAPE; + codeMapping[ 32] = Code.SPACE; + codeMapping[ 33] = Code.PAGE_UP; + codeMapping[ 34] = Code.PAGE_DOWN; + codeMapping[ 35] = Code.END; + codeMapping[ 36] = Code.HOME; + codeMapping[ 37] = Code.LEFT; + codeMapping[ 38] = Code.UP; + codeMapping[ 39] = Code.RIGHT; + codeMapping[ 40] = Code.DOWN; + codeMapping[ 48] = Code.NUMBER_0; + codeMapping[ 49] = Code.NUMBER_1; + codeMapping[ 50] = Code.NUMBER_2; + codeMapping[ 51] = Code.NUMBER_3; + codeMapping[ 52] = Code.NUMBER_4; + codeMapping[ 53] = Code.NUMBER_5; + codeMapping[ 54] = Code.NUMBER_6; + codeMapping[ 55] = Code.NUMBER_7; + codeMapping[ 56] = Code.NUMBER_8; + codeMapping[ 57] = Code.NUMBER_9; + codeMapping[ 65] = Code.LETTER_A; + codeMapping[ 66] = Code.LETTER_B; + codeMapping[ 67] = Code.LETTER_C; + codeMapping[ 68] = Code.LETTER_D; + codeMapping[ 69] = Code.LETTER_E; + codeMapping[ 70] = Code.LETTER_F; + codeMapping[ 71] = Code.LETTER_G; + codeMapping[ 72] = Code.LETTER_H; + codeMapping[ 73] = Code.LETTER_I; + codeMapping[ 74] = Code.LETTER_J; + codeMapping[ 75] = Code.LETTER_K; + codeMapping[ 76] = Code.LETTER_L; + codeMapping[ 77] = Code.LETTER_M; + codeMapping[ 78] = Code.LETTER_N; + codeMapping[ 79] = Code.LETTER_O; + codeMapping[ 80] = Code.LETTER_P; + codeMapping[ 81] = Code.LETTER_Q; + codeMapping[ 82] = Code.LETTER_R; + codeMapping[ 83] = Code.LETTER_S; + codeMapping[ 84] = Code.LETTER_T; + codeMapping[ 85] = Code.LETTER_U; + codeMapping[ 86] = Code.LETTER_V; + codeMapping[ 87] = Code.LETTER_W; + codeMapping[ 88] = Code.LETTER_X; + codeMapping[ 89] = Code.LETTER_Y; + codeMapping[ 90] = Code.LETTER_Z; + codeMapping[ 96] = 228; + codeMapping[ 97] = 231; + codeMapping[ 98] = 227; + codeMapping[ 99] = 233; + codeMapping[100] = 224; + codeMapping[101] = 219; + codeMapping[102] = 225; + codeMapping[103] = 230; + codeMapping[104] = 226; + codeMapping[105] = 232; + codeMapping[106] = 89; + codeMapping[107] = 87; + codeMapping[109] = 88; + codeMapping[110] = 229; + codeMapping[111] = 90; + codeMapping[112] = Code.F1; + codeMapping[113] = Code.F2; + codeMapping[114] = Code.F3; + codeMapping[115] = Code.F4; + codeMapping[116] = Code.F5; + codeMapping[117] = Code.F6; + codeMapping[118] = Code.F7; + codeMapping[119] = Code.F8; + codeMapping[120] = Code.F9; + codeMapping[121] = Code.F10; + codeMapping[122] = Code.F11; + codeMapping[123] = Code.F12; + codeMapping[127] = Code.DELETE; + codeMapping[155] = Code.INSERT; + } + + public static void initializeAdditionalCodeMappings() { + codeMapping[ 44] = 71; + codeMapping[ 45] = 26; + codeMapping[ 46] = 72; + codeMapping[ 47] = Code.FORWARD_SLASH; + codeMapping[ 59] = 57; + codeMapping[ 61] = 27; + codeMapping[ 91] = 42; + codeMapping[ 92] = 74; + codeMapping[ 93] = 43; + codeMapping[192] = 28; + codeMapping[222] = 58; + codeMapping[520] = 59; + } + + + public static volatile int ticksSinceLastKeyEvent = 0; + + public static final int[] keyPressQueue = new int[128]; + + public static int keyPressQueueFront = 0; + public static int keyPressQueueBack = 0; + public static final int[] keyTypeCodeQueue = new int[128]; + + public static final char[] keyTypeCharQueue = new char[128]; + public static int keyTypeQueueFront = 0; + public static int keyTypeQueueBack = 0; + + private static boolean isCharAllowed(final char c) { + if (c == 0) { + return false; + } else if (c >= 128 && (c < 160 || c > 255)) { + for (final char knownChar : Strings.WINDOWS_1252_CHARS) { + if (c == knownChar) { + return true; + } + } + + return false; + } else { + return true; + } + } + + @Override + public synchronized void keyPressed(final KeyEvent var1) { + if (instance != null) { + ticksSinceLastKeyEvent = 0; + final int rawCode = var1.getKeyCode(); + final int mappedCode; + if (rawCode >= 0 && rawCode < codeMapping.length) { + final int var21 = codeMapping[rawCode]; + if ((var21 & 128) == 0) { + mappedCode = var21; + } else { + mappedCode = -1; + } + } else { + mappedCode = -1; + } + + if (mappedCode >= 0) { + if (keyPressQueueBack >= 0) { + keyPressQueue[keyPressQueueBack] = mappedCode; + keyPressQueueBack = (keyPressQueueBack + 1) & 127; + if (keyPressQueueFront == keyPressQueueBack) { + keyPressQueueBack = -1; + } + } + + final int i = (keyTypeQueueBack + 1) & 127; + if (i != keyTypeQueueFront) { + keyTypeCodeQueue[keyTypeQueueBack] = mappedCode; + keyTypeCharQueue[keyTypeQueueBack] = 0; + keyTypeQueueBack = i; + } + } + + final int modifiers = var1.getModifiers(); + if ((modifiers & (CTRL_MASK | ALT_MASK)) != 0 || mappedCode == 10 || mappedCode == 85) { + var1.consume(); + } + } + } + + @Override + public synchronized void keyReleased(final KeyEvent event) { + if (instance != null) { + ticksSinceLastKeyEvent = 0; + final int rawCode = event.getKeyCode(); + final int mappedCode; + if (rawCode >= 0 && rawCode < codeMapping.length) { + mappedCode = codeMapping[rawCode] & -129; + } else { + mappedCode = -1; + } + + if (keyPressQueueBack >= 0 && mappedCode >= 0) { + keyPressQueue[keyPressQueueBack] = ~mappedCode; + keyPressQueueBack = 1 + keyPressQueueBack & 127; + if (keyPressQueueBack == keyPressQueueFront) { + keyPressQueueBack = -1; + } + } + } + + event.consume(); + } + + @Override + public void keyTyped(final KeyEvent event) { + if (instance != null) { + final char c = event.getKeyChar(); + if (c != 0 && c != '\uffff' && isCharAllowed(c)) { + final int i = (keyTypeQueueBack + 1) & 127; + if (i != keyTypeQueueFront) { + keyTypeCodeQueue[keyTypeQueueBack] = -1; + keyTypeCharQueue[keyTypeQueueBack] = c; + keyTypeQueueBack = i; + } + } + } + + event.consume(); + } + + @Override + public synchronized void focusLost(final FocusEvent var1) { + if (instance != null) { + keyPressQueueBack = -1; + } + } + + @Override + public void focusGained(final FocusEvent var1) { + } + + public void attach(final Component c) { + c.setFocusTraversalKeysEnabled(false); + c.addKeyListener(this); + c.addFocusListener(this); + } + + public void detach(final Component c) { + c.removeKeyListener(this); + c.removeFocusListener(this); + keyPressQueueBack = -1; + } +} diff --git a/src/main/java/funorb/awt/MouseControlBackend.java b/src/main/java/funorb/awt/MouseControlBackend.java new file mode 100644 index 0000000..cf6f023 --- /dev/null +++ b/src/main/java/funorb/awt/MouseControlBackend.java @@ -0,0 +1,48 @@ +package funorb.awt; + +import java.awt.Component; +import java.awt.Robot; +import java.awt.image.BufferedImage; + +public final class MouseControlBackend { + private final Robot robot = new Robot(); + private Component cursorComponent; + + public MouseControlBackend() throws Exception { + } + + public void movemouse(final int var1, final int var2) { + this.robot.mouseMove(var1, var2); + } + + public void showcursor(Component var1, final boolean var2) { + if (var2) { + var1 = null; + } else if (var1 == null) { + throw new NullPointerException(); + } + + if (this.cursorComponent != var1) { + if (this.cursorComponent != null) { + this.cursorComponent.setCursor(null); + this.cursorComponent = null; + } + + if (var1 != null) { + var1.setCursor(var1.getToolkit().createCustomCursor(new BufferedImage(1, 1, 2), new java.awt.Point(0, 0), null)); + this.cursorComponent = var1; + } + + } + } + + public void setcustomcursor(final Component var1, final int[] var2, final int var3, final int var4, final java.awt.Point var5) { + if (var2 == null) { + var1.setCursor(null); + } else { + final BufferedImage var6 = new BufferedImage(var3, var4, 2); + var6.setRGB(0, 0, var3, var4, var2, 0, var3); + var1.setCursor(var1.getToolkit().createCustomCursor(var6, var5, null)); + } + } +} diff --git a/src/main/java/funorb/awt/MouseState.java b/src/main/java/funorb/awt/MouseState.java new file mode 100644 index 0000000..525dd57 --- /dev/null +++ b/src/main/java/funorb/awt/MouseState.java @@ -0,0 +1,164 @@ +package funorb.awt; + +import funorb.client.JagexBaseApplet; +import funorb.util.PseudoMonotonicClock; +import org.intellij.lang.annotations.MagicConstant; + +import javax.swing.SwingUtilities; +import java.awt.Component; +import java.awt.Point; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; + +public final class MouseState implements MouseListener, MouseMotionListener, FocusListener { + public static final MouseState instance = new MouseState(); + + @MagicConstant(valuesFromClass = Button.class) + public static volatile int mouseButtonJustClicked = Button.NONE; + @MagicConstant(valuesFromClass = Button.class) + public static volatile int mouseButtonDown = Button.NONE; + public static volatile int mouseX = -1; + public static volatile int mouseY = -1; + public static volatile int pressX = 0; + public static volatile int pressY = 0; + public static volatile int ticksSinceLastMouseEvent = 0; + public static volatile boolean mouseEventReceived = false; + + public void attach(final Component c) { + c.addMouseListener(this); + c.addMouseMotionListener(this); + c.addFocusListener(this); + } + + public void detach(final Component c) { + c.removeMouseListener(this); + c.removeMouseMotionListener(this); + c.removeFocusListener(this); + mouseButtonDown = Button.NONE; + } + + private static Point transform(final MouseEvent event) { + final AffineTransform transform = JagexBaseApplet.getTransform(event.getComponent()); + final Point result = new Point(); + try { + transform.inverseTransform(event.getPoint(), result); + } catch (final NoninvertibleTransformException e) { + throw new RuntimeException(e); + } + return result; + } + + @Override + public synchronized void mouseEntered(final MouseEvent var1) { + if (instance != null) { + ticksSinceLastMouseEvent = 0; + mouseX = var1.getX(); + mouseY = var1.getY(); + mouseEventReceived = true; + } + } + + @Override + public void focusGained(final FocusEvent var1) { + } + + @Override + public void mouseClicked(final MouseEvent var1) { + if (var1.isPopupTrigger()) { + var1.consume(); + } + + } + + @Override + public synchronized void mouseMoved(final MouseEvent var1) { + if (instance != null) { + ticksSinceLastMouseEvent = 0; + final Point point = transform(var1); + mouseX = point.x; + mouseY = point.y; + mouseEventReceived = true; + } + + } + + @Override + public synchronized void mouseDragged(final MouseEvent var1) { + if (instance != null) { + ticksSinceLastMouseEvent = 0; + final Point point = transform(var1); + mouseX = point.x; + mouseY = point.y; + mouseEventReceived = true; + } + + } + + @Override + public synchronized void mouseExited(final MouseEvent var1) { + if (instance != null) { + ticksSinceLastMouseEvent = 0; + mouseX = -1; + mouseY = -1; + mouseEventReceived = true; + } + } + + @Override + public synchronized void mouseReleased(final MouseEvent var1) { + if (instance != null) { + ticksSinceLastMouseEvent = 0; + mouseButtonDown = Button.NONE; + mouseEventReceived = true; + + } + + if (var1.isPopupTrigger()) { + var1.consume(); + } + } + + @Override + public synchronized void mousePressed(final MouseEvent var1) { + if (instance != null) { + ticksSinceLastMouseEvent = 0; + final Point point = transform(var1); + pressX = point.x; + pressY = point.y; + PseudoMonotonicClock.currentTimeMillis(); + if (SwingUtilities.isRightMouseButton(var1)) { + mouseButtonJustClicked = Button.RIGHT; + mouseButtonDown = Button.RIGHT; + } else { + mouseButtonJustClicked = Button.LEFT; + mouseButtonDown = Button.LEFT; + } + + mouseEventReceived = true; + + } + + if (var1.isPopupTrigger()) { + var1.consume(); + } + } + + @Override + public synchronized void focusLost(final FocusEvent var1) { + if (instance != null) { + mouseButtonDown = Button.NONE; + } + + } + + public static final class Button { + public static final int NONE = 0; + public static final int LEFT = 1; + public static final int RIGHT = 2; + } +} diff --git a/src/main/java/funorb/awt/MouseWheelState.java b/src/main/java/funorb/awt/MouseWheelState.java new file mode 100644 index 0000000..161dadc --- /dev/null +++ b/src/main/java/funorb/awt/MouseWheelState.java @@ -0,0 +1,30 @@ +package funorb.awt; + +import java.awt.Component; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; + +public final class MouseWheelState implements MouseWheelListener { + public static final MouseWheelState instance = new MouseWheelState(); + private int rotation = 0; + + public void attach(final Component c) { + c.addMouseWheelListener(this); + } + + public void detach(final Component c) { + c.removeMouseWheelListener(this); + } + + @Override + public synchronized void mouseWheelMoved(final MouseWheelEvent e) { + this.rotation += e.getWheelRotation(); + e.consume(); + } + + public synchronized int poll() { + final int rotation = this.rotation; + this.rotation = 0; + return rotation; + } +} diff --git a/src/main/java/funorb/awt/ScreenBuffer.java b/src/main/java/funorb/awt/ScreenBuffer.java new file mode 100644 index 0000000..c8a4749 --- /dev/null +++ b/src/main/java/funorb/awt/ScreenBuffer.java @@ -0,0 +1,22 @@ +package funorb.awt; + +import funorb.graphics.Drawing; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Image; + +public abstract class ScreenBuffer { + protected int[] screenBuffer; + public int width; + protected Image screenBufferImage; + public int height; + + public abstract void initialize(Component canvas, int width, int height); + + protected final void makeGlobal() { + Drawing.initialize(this.screenBuffer, this.width, this.height); + } + + public abstract void paint(Graphics var1); +} diff --git a/src/main/java/funorb/cache/BufferedCacheFile.java b/src/main/java/funorb/cache/BufferedCacheFile.java new file mode 100644 index 0000000..df1a71d --- /dev/null +++ b/src/main/java/funorb/cache/BufferedCacheFile.java @@ -0,0 +1,158 @@ +package funorb.cache; + +import java.io.EOFException; +import java.io.IOException; + +public final class BufferedCacheFile { + private final CacheFile cacheFile; + private final byte[] buffer; + private int _a; + private long physicalPos = 0L; + private long _h; + private long logicalPos = 0L; + private long _l; + private long _i = -1L; + + public BufferedCacheFile(final CacheFile cacheFile, final int bufferSize) throws IOException { + this.cacheFile = cacheFile; + this._h = this._l = cacheFile.length(); + this.buffer = new byte[bufferSize]; + } + + public void write(final byte[] data, final int offset, final int len) throws IOException { + try { + if ((long) len + this.logicalPos > this._h) { + this._h = this.logicalPos + (long) len; + } + + if (len > 0) { + if (this.physicalPos != this.logicalPos) { + this.cacheFile.seek(this.logicalPos); + this.physicalPos = this.logicalPos; + } + + this.cacheFile.write(data, offset, len); + this.physicalPos += len; + if (this.physicalPos > this._l) { + this._l = this.physicalPos; + } + + final long var6; + if (this.logicalPos >= this._i && this.logicalPos < this._i + (long) this._a) { + var6 = this.logicalPos; + } else if (this._i >= this.logicalPos && this._i < this.logicalPos + (long) len) { + var6 = this._i; + } else { + var6 = -1; + } + + final long var8; + if (this.logicalPos + (long) len > this._i && (long) this._a + this._i >= this.logicalPos + (long) len) { + var8 = (long) len + this.logicalPos; + } else if (this._i + (long) this._a > this.logicalPos && this.logicalPos + (long) len >= (long) this._a + this._i) { + var8 = (long) this._a + this._i; + } else { + var8 = -1; + } + + if (var6 > -1L && var6 < var8) { + final int var10 = (int) (var8 - var6); + System.arraycopy(data, (int) (var6 + (long) offset - this.logicalPos), this.buffer, (int) (var6 - this._i), var10); + } + + this.logicalPos += len; + } + } catch (final IOException e) { + this.physicalPos = -1L; + throw e; + } + } + + private void pageIn() throws IOException { + if (this.logicalPos != this.physicalPos) { + this.cacheFile.seek(this.logicalPos); + this.physicalPos = this.logicalPos; + } + this._i = this.logicalPos; + + for (this._a = 0; this._a < this.buffer.length;) { + final int len = Math.min(this.buffer.length - this._a, 200000000); + final int bytesRead = this.cacheFile.read(this.buffer, this._a, len); + if (bytesRead == -1) { + break; + } + + this._a += bytesRead; + this.physicalPos += bytesRead; + } + } + + public void read(final byte[] dest, final int len) throws IOException { + int lenLeft = len; + try { + if (dest.length < len) { + throw new ArrayIndexOutOfBoundsException(len - 1); + } + + int var4 = 0; + if (this._i <= this.logicalPos && (long) this._a + this._i > this.logicalPos) { + final int var9 = Math.min((int) ((long) this._a - this.logicalPos + this._i), lenLeft); + System.arraycopy(this.buffer, (int) (this.logicalPos - this._i), dest, var4, var9); + this.logicalPos += var9; + lenLeft -= var9; + var4 += var9; + } + + if (lenLeft <= this.buffer.length) { + if (lenLeft > 0) { + this.pageIn(); + final int var10 = Math.min(lenLeft, this._a); + System.arraycopy(this.buffer, 0, dest, var4, var10); + this.logicalPos += var10; + lenLeft -= var10; + } + } else { + this.cacheFile.seek(this.logicalPos); + int var10; + for (this.physicalPos = this.logicalPos; lenLeft > 0; var4 += var10) { + var10 = this.cacheFile.read(dest, var4, lenLeft); + if (var10 == -1) { + break; + } + + lenLeft -= var10; + this.physicalPos += var10; + this.logicalPos += var10; + } + } + + } catch (final IOException e) { + this.physicalPos = -1L; + throw e; + } + + if (lenLeft > 0) { + throw new EOFException(); + } + } + + public void read(final byte[] dest) throws IOException { + this.read(dest, dest.length); + } + + public long length() { + return this._h; + } + + public void seek(final long pos) throws IOException { + if (pos >= 0L) { + this.logicalPos = pos; + } else { + throw new IOException(); + } + } + + public void close() throws IOException { + this.cacheFile.close(); + } +} diff --git a/src/main/java/funorb/cache/BufferedPageCache.java b/src/main/java/funorb/cache/BufferedPageCache.java new file mode 100644 index 0000000..ae8a6e0 --- /dev/null +++ b/src/main/java/funorb/cache/BufferedPageCache.java @@ -0,0 +1,250 @@ +package funorb.cache; + +import org.intellij.lang.annotations.MagicConstant; + +import java.io.EOFException; +import java.io.IOException; + +public final class BufferedPageCache { + private static final int INDEX_ENTRY_SIZE = 6; + private static final int MAX_DATA_ENTRY_SIZE = 0x200000; + // an 8-byte header + 512 bytes of data, or a 10-byte header + 510 bytes of data for high indexes + private static final int DATA_ENTRY_BLOCK_SIZE = 520; + + private static final byte[] buffer = new byte[DATA_ENTRY_BLOCK_SIZE]; + private final BufferedCacheFile indexFile; + private final BufferedCacheFile dataFile; + @MagicConstant(valuesFromClass = ResourceLoader.PageId.class) + private final int pageId; + + public BufferedPageCache(@MagicConstant(valuesFromClass = ResourceLoader.PageId.class) final int pageId, final BufferedCacheFile dataFile, final BufferedCacheFile indexFile) { + this.pageId = pageId; + this.dataFile = dataFile; + this.indexFile = indexFile; + } + + @Override + public String toString() { + return "" + this.pageId; + } + + public byte[] read(final int groupId) { + synchronized (this.dataFile) { + try { + if ((groupId + 1) * (long) INDEX_ENTRY_SIZE > this.indexFile.length()) { + return null; + } + + this.indexFile.seek(groupId * (long) INDEX_ENTRY_SIZE); + this.indexFile.read(buffer, 6); + final int len = ((buffer[0] & 0xff) << 16) + ((buffer[1] & 0xff) << 8) + (buffer[2] & 0xff); + if (len > MAX_DATA_ENTRY_SIZE) { + return null; + } + + int slot = ((buffer[3] & 0xff) << 16) + ((buffer[4] & 0xff) << 8) + (buffer[5] & 0xff); + if (slot <= 0 || (long) slot > this.dataFile.length() / DATA_ENTRY_BLOCK_SIZE) { + return null; + } + + final byte[] data = new byte[len]; + int bytesRead = 0; + int part = 0; + while (bytesRead < len) { + if (slot == 0) { + return null; + } + + final int bytesLeft = len - bytesRead; + final boolean isSmallIndex = groupId <= 0xffff; + final int blockHeaderLen = isSmallIndex ? 8 : 10; + final int blockDataLen = Math.min(bytesLeft, DATA_ENTRY_BLOCK_SIZE - blockHeaderLen); + final int blockLen = blockHeaderLen + blockDataLen; + + this.dataFile.seek(slot * (long) DATA_ENTRY_BLOCK_SIZE); + this.dataFile.read(buffer, blockLen); + final int entryIndex; + final int entryPart; + final int nextSlot; + final int indexId; + if (isSmallIndex) { + entryIndex = ((buffer[0] & 0xff) << 8) + (buffer[1] & 0xff); + entryPart = ((buffer[2] & 0xff) << 8) + (buffer[3] & 0xff); + nextSlot = ((buffer[4] & 0xff) << 16) + ((buffer[5] & 0xff) << 8) + (buffer[6] & 0xff); + indexId = buffer[7] & 0xff; + } else { + entryIndex = ((buffer[0] & 0xff) << 24) + ((buffer[1] & 0xff) << 16) + ((buffer[2] & 0xff) << 8) + (buffer[3] & 0xff); + entryPart = ((buffer[4] & 0xff) << 8) + (buffer[5] & 0xff); + nextSlot = ((buffer[6] & 0xff) << 16) + ((buffer[7] & 0xff) << 8) + (buffer[8] & 0xff); + indexId = buffer[9] & 0xff; + } + + //noinspection MagicConstant + if (entryIndex != groupId || entryPart != part || this.pageId != indexId) { + return null; + } + if ((long) nextSlot > this.dataFile.length() / DATA_ENTRY_BLOCK_SIZE) { + return null; + } + + for (int i = blockHeaderLen; i < blockLen; ++i) { + data[bytesRead++] = buffer[i]; + } + + slot = nextSlot; + ++part; + } + + return data; + } catch (final IOException e) { + return null; + } + } + } + + public void write(final int groupId, final byte[] data, final int len) { + synchronized (this.dataFile) { + if (len >= 0 && len <= MAX_DATA_ENTRY_SIZE) { + final boolean var6 = this.write(groupId, data, len, true); + if (!var6) { + this.write(groupId, data, len, false); + } + } else { + throw new IllegalArgumentException(); + } + } + } + + private boolean write(final int groupId, final byte[] data, final int len, boolean replaceExisting) { + synchronized (this.dataFile) { + try { + int slot; + if (replaceExisting) { + if (this.indexFile.length() < (groupId + 1) * 6L) { + return false; + } + + this.indexFile.seek(groupId * (long) INDEX_ENTRY_SIZE); + this.indexFile.read(buffer, INDEX_ENTRY_SIZE); + slot = ((buffer[3] & 255) << 16) + + ((buffer[4] & 255) << 8) + + (buffer[5] & 255); + if (slot <= 0 || (long) slot > this.dataFile.length() / DATA_ENTRY_BLOCK_SIZE) { + return false; + } + } else { + slot = (int) ((this.dataFile.length() + (DATA_ENTRY_BLOCK_SIZE - 1L)) / DATA_ENTRY_BLOCK_SIZE); + if (slot == 0) { + slot = 1; + } + } + + buffer[0] = (byte) (len >> 16); + buffer[1] = (byte) (len >> 8); + buffer[2] = (byte) len; + buffer[3] = (byte) (slot >> 16); + buffer[4] = (byte) (slot >> 8); + buffer[5] = (byte) slot; + this.indexFile.seek(groupId * (long) INDEX_ENTRY_SIZE); + this.indexFile.write(buffer, 0, 6); + + int bytesWritten = 0; + int part = 0; + while (len > bytesWritten) { + int nextSlot = 0; + if (replaceExisting) { + final int entryIndex; + this.dataFile.seek(slot * (long) DATA_ENTRY_BLOCK_SIZE); + final int entryPart; + final int indexId; + if (groupId <= 0xffff) { + try { + this.dataFile.read(buffer, 8); + } catch (final EOFException e) { + return true; + } + + entryIndex = ((buffer[0] & 0xff) << 8) + (buffer[1] & 0xff); + entryPart = ((buffer[2] & 0xff) << 8) + (buffer[3] & 0xff); + nextSlot = ((buffer[4] & 0xff) << 16) + ((buffer[5] & 0xff) << 8) + (buffer[6] & 0xff); + indexId = buffer[7] & 0xff; + } else { + try { + this.dataFile.read(buffer, 10); + } catch (final EOFException e) { + return true; + } + + entryIndex = ((buffer[0] & 0xff) << 24) + ((buffer[1] & 0xff) << 16) + ((buffer[2] & 0xff) << 8) + (buffer[3] & 0xff); + entryPart = ((buffer[4] & 0xff) << 8) + (buffer[5] & 0xff); + nextSlot = ((buffer[6] & 0xff) << 16) + ((buffer[7] & 0xff) << 8) + (buffer[8] & 0xff); + indexId = buffer[9] & 0xff; + } + + //noinspection MagicConstant + if (entryIndex != groupId || entryPart != part || indexId != this.pageId) { + return false; + } + + if ((long) nextSlot > this.dataFile.length() / DATA_ENTRY_BLOCK_SIZE) { + return false; + } + } + + if (nextSlot == 0) { + replaceExisting = false; + nextSlot = (int) ((this.dataFile.length() + (DATA_ENTRY_BLOCK_SIZE - 1L)) / DATA_ENTRY_BLOCK_SIZE); + if (nextSlot == 0) { + ++nextSlot; + } + + if (nextSlot == slot) { + ++nextSlot; + } + } + + if (len - bytesWritten <= 512) { + nextSlot = 0; // no next part, so no next slot + } + + final int entryLen; + if (groupId <= 0xffff) { + buffer[0] = (byte) (groupId >> 8); + buffer[1] = (byte) groupId; + buffer[2] = (byte) (part >> 8); + buffer[3] = (byte) part; + buffer[4] = (byte) (nextSlot >> 16); + buffer[5] = (byte) (nextSlot >> 8); + buffer[6] = (byte) nextSlot; + buffer[7] = (byte) this.pageId; + this.dataFile.seek(slot * (long) DATA_ENTRY_BLOCK_SIZE); + this.dataFile.write(buffer, 0, 8); + entryLen = Math.min(len - bytesWritten, 512); + } else { + buffer[0] = (byte) (groupId >> 24); + buffer[1] = (byte) (groupId >> 16); + buffer[2] = (byte) (groupId >> 8); + buffer[3] = (byte) groupId; + buffer[4] = (byte) (part >> 8); + buffer[5] = (byte) part; + buffer[6] = (byte) (nextSlot >> 16); + buffer[7] = (byte) (nextSlot >> 8); + buffer[8] = (byte) nextSlot; + buffer[9] = (byte) this.pageId; + this.dataFile.seek(slot * (long) DATA_ENTRY_BLOCK_SIZE); + this.dataFile.write(buffer, 0, 10); + entryLen = Math.min(len - bytesWritten, 510); + } + this.dataFile.write(data, bytesWritten, entryLen); + bytesWritten += entryLen; + + ++part; + slot = nextSlot; + } + return true; + } catch (final IOException var18) { + return false; + } + } + } +} diff --git a/src/main/java/funorb/cache/CacheFile.java b/src/main/java/funorb/cache/CacheFile.java new file mode 100644 index 0000000..9e225aa --- /dev/null +++ b/src/main/java/funorb/cache/CacheFile.java @@ -0,0 +1,110 @@ +package funorb.cache; + +import funorb.shatteredplans.client.MessagePumpThread; + +import java.io.Closeable; +import java.io.EOFException; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public final class CacheFile implements Closeable { + private static final Path BASE_DIRECTORY = Paths.get(System.getProperty("user.home"), ".alterorb"); + private static final Path CACHES_DIRECTORY = BASE_DIRECTORY.resolve("caches"); + + private final long maxSize; + private long pos; + private RandomAccessFile file; + + public CacheFile(final File file, long maxSize) throws IOException { + if (maxSize == -1L) { + maxSize = Long.MAX_VALUE; + } + + if (maxSize < file.length()) { + //noinspection ResultOfMethodCallIgnored + file.delete(); + } + + this.file = new RandomAccessFile(file, "rw"); + this.maxSize = maxSize; + this.pos = 0L; + final int var5 = this.file.read(); + if (var5 != -1) { + this.file.seek(0L); + this.file.write(var5); + } + + this.file.seek(0L); + } + + public static File path(final String var0, final String var2) { + try { + final var path = cacheFilePath(var2, var0); + if (!Files.exists(path)) { + Files.createDirectories(path.getParent()); + } + return path.toFile(); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + + public static File path(final String var0) { + return path(var0, MessagePumpThread.GAME_ID); + } + + private static Path cacheFilePath(final String subDirectory, final String file) { + if (subDirectory != null) { + return CACHES_DIRECTORY.resolve(subDirectory).resolve(file); + } + return CACHES_DIRECTORY.resolve(file); + } + + public int read(final byte[] buffer, final int offset, final int len) throws IOException { + final int bytesRead = this.file.read(buffer, offset, len); + if (bytesRead > 0) { + this.pos += bytesRead; + } + return bytesRead; + } + + public long length() throws IOException { + return this.file.length(); + } + + @Override + public void close() throws IOException { + if (this.file != null) { + this.file.close(); + this.file = null; + } + } + + @Override + protected void finalize() throws Throwable { + if (this.file != null) { + System.out.println(); + this.close(); + } + } + + public void seek(final long pos) throws IOException { + this.file.seek(pos); + this.pos = pos; + } + + public void write(final byte[] data, final int offset, final int len) throws IOException { + if (this.pos + (long) len <= this.maxSize) { + this.file.write(data, offset, len); + this.pos += len; + } else { + this.file.seek(this.maxSize); + this.file.write(1); + throw new EOFException(); + } + } +} diff --git a/src/main/java/funorb/cache/CacheWorker.java b/src/main/java/funorb/cache/CacheWorker.java new file mode 100644 index 0000000..eb58ee0 --- /dev/null +++ b/src/main/java/funorb/cache/CacheWorker.java @@ -0,0 +1,159 @@ +package funorb.cache; + +import funorb.shatteredplans.client.MailboxMessage; +import funorb.shatteredplans.client.MessagePumpThread; + +import java.io.Closeable; +import java.util.ArrayDeque; +import java.util.Queue; +import java.util.function.Function; + +/** + * A {@link CacheWorker} mediates reads and writes to the local resource cache. + * It maintains a queue of {@link WorkItem}s and processes them in the + * background, ensuring all reads and writes to the cache are serialized. + */ +public final class CacheWorker implements Runnable, Closeable { + public static CacheWorker instance; + + private final Queue pending = new ArrayDeque<>(); + public int pendingCount = 0; + private Thread thread; + private boolean shutdownRequested = false; + + public CacheWorker(final Function createThread) { + this.thread = createThread.apply(this); + } + + public static CacheWorker create(final MessagePumpThread messagePumpThread) { + return new CacheWorker(self -> { + final MailboxMessage message = messagePumpThread.sendSpawnThreadMessage(self, 5); + if (message.busyAwait() == MailboxMessage.Status.FAILURE) { + throw new RuntimeException(); + } else { + return (Thread) message.response; + } + }); + } + + @Override + public void run() { + while (!this.shutdownRequested) { + final WorkItem req; + synchronized (this.pending) { + req = this.pending.poll(); + if (req == null) { + try { + this.pending.wait(); + } catch (final InterruptedException var5) {} + continue; + } + + --this.pendingCount; + } + + if (req.type == WorkItem.Type.WRITE) { + req.cacheFile.write(req.groupId, req.data, req.data.length); + } else if (req.type == WorkItem.Type.READ) { + req.data = req.cacheFile.read(req.groupId); + } else { + throw new IllegalStateException(); + } + + req.setLoaded(); + } + } + + private void enqueue(final WorkItem req) { + synchronized (this.pending) { + this.pending.add(req); + ++this.pendingCount; + this.pending.notifyAll(); + } + } + + public void enqueueWrite(final BufferedPageCache cacheFile, final int groupId, final byte[] data) { + final WorkItem req = new WorkItem(WorkItem.Type.WRITE, cacheFile, false); + req.groupId = groupId; + req.data = data; + this.enqueue(req); + } + + public WorkItem enqueueRead(final BufferedPageCache cacheFile, final int groupId) { + final WorkItem req = new WorkItem(WorkItem.Type.READ, cacheFile, false); + req.groupId = groupId; + this.enqueue(req); + return req; + } + + /** + * Performs an immediate read, blocking until the read has been + * performed. If there are any pending writes to the cache for the given + * group, the pending written data will be returned. Otherwise, the data is + * fetched via a call to {@link BufferedPageCache#read(int)}. Note that the + * returned data may be {@code null} in the case of a cache miss. + */ + public WorkItem tryRead(final BufferedPageCache cacheFile, final int groupId) { + synchronized (this.pending) { + for (final WorkItem next : this.pending) { + if (next.groupId == groupId && next.cacheFile == cacheFile && next.type == WorkItem.Type.WRITE) { + assert next.data != null; + final WorkItem req = new WorkItem(WorkItem.Type.TRY_READ, null, false); + req.data = next.data; + req.setLoaded(); + return req; + } + } + } + + final WorkItem req = new WorkItem(WorkItem.Type.TRY_READ, null, true); + req.data = cacheFile.read(groupId); + req.setLoaded(); + return req; + } + + @Override + public void close() { + this.shutdownRequested = true; + synchronized (this.pending) { + this.pending.notifyAll(); + } + + try { + this.thread.join(); + } catch (final InterruptedException var4) {} + + this.thread = null; + } + + public static final class WorkItem extends PageLoader.WorkItem { + private enum Type { + TRY_READ, WRITE, READ + } + + private final Type type; + private final BufferedPageCache cacheFile; + private byte[] data; + private int groupId; + public final boolean isTryWithoutWrite; + + private WorkItem(final Type type, final BufferedPageCache cacheFile, final boolean isTryWithoutWrite) { + this.type = type; + this.cacheFile = cacheFile; + this.isTryWithoutWrite = isTryWithoutWrite; + } + + @Override + public int percentLoaded() { + return this.isLoaded() ? 100 : 0; + } + + @Override + public byte[] getData() { + if (!this.isLoaded()) { + throw new IllegalStateException("not yet loaded"); + } + return this.data; + } + } +} diff --git a/src/main/java/funorb/cache/LocalPageSource.java b/src/main/java/funorb/cache/LocalPageSource.java new file mode 100644 index 0000000..9aaf7c3 --- /dev/null +++ b/src/main/java/funorb/cache/LocalPageSource.java @@ -0,0 +1,33 @@ +package funorb.cache; + +import funorb.io.Buffer; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.io.InputStream; +import java.util.function.BiFunction; + +public final class LocalPageSource extends PageSource { + private final BiFunction open; + + public LocalPageSource(final BiFunction open) { + this.open = open; + } + + @Override + protected void enqueue(final @NotNull WorkItem item) { + final int pageId = (int) (item.partId >> 32); + final int part = (int) item.partId; + try (final InputStream in = this.open.apply(pageId, part)) { + final byte[] data = in.readAllBytes(); + item.buffer = new Buffer(data.length + item.extraBytes); + item.buffer.writeBytes(data); + } catch (final IOException e) { + throw new RuntimeException(e); + } + item.setLoaded(); + } + + @Override + public void closeDueToError() {} +} diff --git a/src/main/java/funorb/cache/MasterIndexLoader.java b/src/main/java/funorb/cache/MasterIndexLoader.java new file mode 100644 index 0000000..1ffca5b --- /dev/null +++ b/src/main/java/funorb/cache/MasterIndexLoader.java @@ -0,0 +1,85 @@ +package funorb.cache; + +import funorb.io.Buffer; +import funorb.util.Whirlpool; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public final class MasterIndexLoader { + private final @NotNull PageSource pageSource; + private final @NotNull CacheWorker cacheWorker; + + private PageSource.WorkItem loadRequest; + private Buffer buffer; + private PageLoader[] pageLoaders; + + public MasterIndexLoader(final @NotNull PageSource pageSource, final @NotNull CacheWorker cacheWorker) { + this.pageSource = pageSource; + this.cacheWorker = cacheWorker; + this.loadRequest = this.pageSource.enqueueLoad(ResourceLoader.PageId.INDEX, 255, (byte) 0); + } + + public boolean loadIndex() { + if (this.buffer != null) { + return true; + } + if (this.loadRequest == null) { + this.loadRequest = this.pageSource.enqueueLoad(ResourceLoader.PageId.INDEX, 255, (byte) 0); + } + if (!this.loadRequest.isLoaded()) { + return false; + } + + final Buffer buffer = new Buffer(this.loadRequest.getData()); + buffer.pos = 5; + final int partCount = buffer.readUByte(); + buffer.pos += partCount * 72; + final byte[] remoteHash = new byte[buffer.data.length - buffer.pos]; + buffer.readBytes(remoteHash, remoteHash.length); + + if (remoteHash.length != 65) { + throw new AssertionError(); + } + Whirlpool.checkHash(buffer.data, 5, buffer.pos - remoteHash.length - 5, remoteHash, 1); + + this.pageLoaders = new PageLoader[partCount]; + this.buffer = buffer; + return true; + } + + public PageLoader getPageLoader(final int pageId, final @Nullable BufferedPageCache masterIndexCache, final @NotNull BufferedPageCache pageCache) { + if (this.buffer == null) { + throw new IllegalStateException(); + } + if (pageId < 0 || this.pageLoaders.length <= pageId) { + throw new RuntimeException(); + } + if (this.pageLoaders[pageId] == null) { + this.buffer.pos = 6 + pageId * 72; + final int crc = this.buffer.readInt(); + final int version = this.buffer.readInt(); + final byte[] whirlpoolHash = new byte[Whirlpool.HASH_BYTES]; + this.buffer.readBytes(whirlpoolHash); + final PageLoader entry = new PageLoader(pageId, pageCache, masterIndexCache, this.pageSource, this.cacheWorker, crc, whirlpoolHash, version); + this.pageLoaders[pageId] = entry; + return entry; + } else { + return this.pageLoaders[pageId]; + } + } + + public void tick() { + if (this.pageLoaders != null) { + for (final PageLoader pageLoader : this.pageLoaders) { + if (pageLoader != null) { + pageLoader.tryGetOrCreateIndex(); + } + } + for (final PageLoader pageLoader : this.pageLoaders) { + if (pageLoader != null) { + pageLoader.tick(); + } + } + } + } +} diff --git a/src/main/java/funorb/cache/PageIndex.java b/src/main/java/funorb/cache/PageIndex.java new file mode 100644 index 0000000..d780c46 --- /dev/null +++ b/src/main/java/funorb/cache/PageIndex.java @@ -0,0 +1,209 @@ +package funorb.cache; + +import funorb.io.Buffer; +import funorb.io.Bzip2; +import funorb.io.Inflater; +import funorb.util.ArrayUtil; +import funorb.util.Whirlpool; + +public final class PageIndex { + public ResourceDirectory groupDirectory; + public ResourceDirectory[] itemDirectories; + public final int pageVersion; + public final int groupCount; + public final int[] groupIndexes; + public final int[] groupSizes; + public final int[] itemCounts; + public final int[][] itemIdMaps; + public byte[][] groupWhirlpoolHashes; + public final int[] _v; + public final int[] groupCrcs; + + public PageIndex(final byte[] data, final int expectedCrc, final byte[] expectedWhirlpool) { + final int crc = Buffer.computeCrc(data, data.length); + if (crc != expectedCrc) { + throw new RuntimeException(); + } + if (expectedWhirlpool != null) { + if (expectedWhirlpool.length != 64) { + throw new RuntimeException(); + } + Whirlpool.checkHash(data, 0, data.length, expectedWhirlpool); + } + + final Buffer buffer = new Buffer(decompress(data)); + final int var4 = buffer.readUByte(); + if (var4 < 5 || var4 > 7) { + throw new RuntimeException(); + } + + if (var4 >= 6) { + this.pageVersion = buffer.readInt(); + } else { + this.pageVersion = 0; + } + + final int flags = buffer.readUByte(); + final boolean var6 = (flags & 1) != 0; + final boolean hasWhirlpool = (flags & 2) != 0; + + final int len = var4 == 7 ? buffer.readVariable16_32() : buffer.readUShort(); + int var8 = 0; + this.groupIndexes = new int[len]; + int highestEntryIndex = -1; + if (var4 == 7) { + for (int i = 0; i < len; ++i) { + this.groupIndexes[i] = var8 += buffer.readVariable16_32(); + if (highestEntryIndex < this.groupIndexes[i]) { + highestEntryIndex = this.groupIndexes[i]; + } + } + } else { + for (int i = 0; i < len; ++i) { + this.groupIndexes[i] = var8 += buffer.readUShort(); + if (highestEntryIndex < this.groupIndexes[i]) { + highestEntryIndex = this.groupIndexes[i]; + } + } + } + + this.groupCount = highestEntryIndex + 1; + this.itemIdMaps = new int[this.groupCount][]; + this.itemCounts = new int[this.groupCount]; + this.groupSizes = new int[this.groupCount]; + this.groupCrcs = new int[this.groupCount]; + if (hasWhirlpool) { + this.groupWhirlpoolHashes = new byte[this.groupCount][]; + } + + this._v = new int[this.groupCount]; + if (var6) { + final int[] _s = ArrayUtil.create(this.groupCount, -1); + for (int i = 0; i < len; ++i) { + _s[this.groupIndexes[i]] = buffer.readInt(); + } + this.groupDirectory = new ResourceDirectory(_s); + } + + for (int i = 0; i < len; ++i) { + this.groupCrcs[this.groupIndexes[i]] = buffer.readInt(); + } + + if (hasWhirlpool) { + for (int i = 0; len > i; ++i) { + final byte[] var11 = new byte[64]; + buffer.readBytes(var11, 64); + this.groupWhirlpoolHashes[this.groupIndexes[i]] = var11; + } + } + + for (int i = 0; i < len; ++i) { + this._v[this.groupIndexes[i]] = buffer.readInt(); + } + + if (var4 == 7) { + for (int i = 0; len > i; ++i) { + this.itemCounts[this.groupIndexes[i]] = buffer.readVariable16_32(); + } + + for (int i = 0; i < len; ++i) { + final int var16 = this.groupIndexes[i]; + final int var12 = this.itemCounts[var16]; + var8 = 0; + this.itemIdMaps[var16] = new int[var12]; + int var13 = -1; + + for (int j = 0; var12 > j; ++j) { + final int var15 = this.itemIdMaps[var16][j] = var8 += buffer.readVariable16_32(); + if (var15 > var13) { + var13 = var15; + } + } + + this.groupSizes[var16] = var13 + 1; + if (var12 == var13 + 1) { + this.itemIdMaps[var16] = null; + } + } + } else { + for (int i = 0; i < len; ++i) { + this.itemCounts[this.groupIndexes[i]] = buffer.readUShort(); + } + + for (int i = 0; i < len; ++i) { + final int var16 = this.groupIndexes[i]; + var8 = 0; + final int var12 = this.itemCounts[var16]; + int var13 = -1; + this.itemIdMaps[var16] = new int[var12]; + + for (int var14 = 0; var12 > var14; ++var14) { + final int var15 = this.itemIdMaps[var16][var14] = var8 += buffer.readUShort(); + if (var13 < var15) { + var13 = var15; + } + } + + this.groupSizes[var16] = 1 + var13; + if (var13 + 1 == var12) { + this.itemIdMaps[var16] = null; + } + } + } + + if (var6) { + final int[][] _t = new int[1 + highestEntryIndex][]; + this.itemDirectories = new ResourceDirectory[highestEntryIndex + 1]; + + for (int i = 0; len > i; ++i) { + final int var16 = this.groupIndexes[i]; + final int var12 = this.itemCounts[var16]; + _t[var16] = new int[this.groupSizes[var16]]; + + for (int var13 = 0; this.groupSizes[var16] > var13; ++var13) { + _t[var16][var13] = -1; + } + + for (int var13 = 0; var13 < var12; ++var13) { + final int var14; + if (this.itemIdMaps[var16] == null) { + var14 = var13; + } else { + var14 = this.itemIdMaps[var16][var13]; + } + + _t[var16][var14] = buffer.readInt(); + } + + this.itemDirectories[var16] = new ResourceDirectory(_t[var16]); + } + } + } + + public static byte[] decompress(final byte[] data) { + final Buffer buffer = new Buffer(data); + final int compressionFormat = buffer.readUByte(); + final int dataLen = buffer.readInt(); + if (dataLen < 0) { + throw new RuntimeException("negative data length"); + } + + if (compressionFormat == 0) { + final byte[] result = new byte[dataLen]; + buffer.readBytes(result); + return result; + } + + final int compressedLen = buffer.readInt(); + if (compressedLen < 0) { + throw new RuntimeException("negative compressed data length"); + } + final byte[] result = new byte[compressedLen]; + if (compressionFormat == 1) { + Bzip2.decompress(data, result); + } else { + Inflater.inflate(buffer, result); + } + return result; + } +} diff --git a/src/main/java/funorb/cache/PageLoader.java b/src/main/java/funorb/cache/PageLoader.java new file mode 100644 index 0000000..583e142 --- /dev/null +++ b/src/main/java/funorb/cache/PageLoader.java @@ -0,0 +1,272 @@ +package funorb.cache; + +import funorb.util.Whirlpool; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.zip.CRC32; + +public final class PageLoader { + private static final CRC32 CRC_32 = new CRC32(); + + private final int pageId; + private final @NotNull BufferedPageCache pageCache; + private final @Nullable BufferedPageCache masterIndexCache; + private final @NotNull PageSource pageSource; + private final @NotNull CacheWorker cacheWorker; + private final int pageCrc; + private final byte@NotNull[] pageExpectedWhirlpool; + private final int pageVersion; + + private PageIndex index; + private WorkItem indexItem; + private final Map dataItems = new HashMap<>(); + private Collection pendingGroups = new ArrayList<>(); + private @Nullable GroupStatus[] groupStatuses; + private int nextGroupId = 0; + + public PageLoader(final int pageId, + final @NotNull BufferedPageCache pageCache, + final @Nullable BufferedPageCache masterIndexCache, + final @NotNull PageSource pageSource, + final @NotNull CacheWorker cacheWorker, + final int pageCrc, + final byte@NotNull[] pageExpectedWhirlpool, + final int pageVersion) { + this.pageId = pageId; + this.pageCache = pageCache; + this.masterIndexCache = masterIndexCache; + this.pageSource = pageSource; + this.cacheWorker = cacheWorker; + this.pageCrc = pageCrc; + this.pageExpectedWhirlpool = pageExpectedWhirlpool; + this.pageVersion = pageVersion; + if (this.masterIndexCache != null) { + this.indexItem = this.cacheWorker.tryRead(this.masterIndexCache, this.pageId); + } + } + + public void tick() { + if (this.pendingGroups != null) { + if (this.tryGetOrCreateIndex() == null) { + return; + } + + boolean isLoaded = true; + for (final Iterator it = this.pendingGroups.iterator(); it.hasNext(); ) { + final Integer groupId = it.next(); + if (this.groupStatuses[groupId] == null) { + this.tryLoadGroup(LoadMethod.READ_FROM_CACHE, groupId); + } + if (this.groupStatuses[groupId] == null) { + isLoaded = false; + } else { + it.remove(); + } + } + + while (this.nextGroupId < this.index.itemCounts.length) { + if (this.index.itemCounts[this.nextGroupId] != 0) { + if (this.cacheWorker.pendingCount >= 250) { + isLoaded = false; + break; + } + + if (this.groupStatuses[this.nextGroupId] == null) { + this.tryLoadGroup(LoadMethod.READ_FROM_CACHE, this.nextGroupId); + } + + if (this.groupStatuses[this.nextGroupId] == null) { + isLoaded = false; + this.pendingGroups.add(this.nextGroupId); + } + } + ++this.nextGroupId; + } + + if (isLoaded) { + this.nextGroupId = 0; + this.pendingGroups = null; + } + } + } + + public @Nullable PageIndex tryGetOrCreateIndex() { + if (this.index != null) { + return this.index; + } + if (this.indexItem == null) { + this.indexItem = this.pageSource.enqueueLoad(ResourceLoader.PageId.INDEX, this.pageId, (byte) 0); + } + if (!this.indexItem.isLoaded()) { + return null; + } + + final byte[] data = this.indexItem.getData(); + if (this.indexItem instanceof CacheWorker.WorkItem) { + try { + if (data == null) { + throw new RuntimeException(); + } + this.index = new PageIndex(data, this.pageCrc, this.pageExpectedWhirlpool); + if (this.pageVersion != this.index.pageVersion) { + throw new RuntimeException(); + } + } catch (final RuntimeException e) { + this.index = null; + this.indexItem = this.pageSource.enqueueLoad(ResourceLoader.PageId.INDEX, this.pageId, (byte) 0); + return null; + } + } else { + try { + if (data == null) { + throw new RuntimeException(); + } + this.index = new PageIndex(data, this.pageCrc, this.pageExpectedWhirlpool); + } catch (final RuntimeException e) { + this.pageSource.closeDueToError(); + this.index = null; + this.indexItem = this.pageSource.enqueueLoad(ResourceLoader.PageId.INDEX, this.pageId, (byte) 0); + return null; + } + + if (this.masterIndexCache != null) { + this.cacheWorker.enqueueWrite(this.masterIndexCache, this.pageId, data); + } + } + + this.indexItem = null; + this.groupStatuses = new GroupStatus[this.index.groupCount]; + return this.index; + } + + public int percentLoaded(final int groupId) { + final WorkItem item = this.dataItems.get(groupId); + return item != null ? item.percentLoaded() : 0; + } + + public byte@Nullable[] tryGetLoadedData(final int groupId) { + final WorkItem item = this.tryLoadGroup(LoadMethod.TRY_CACHE_ELSE_FETCH, groupId); + if (item == null) { + return null; + } + this.dataItems.remove(groupId); + return item.getData(); + } + + private @Nullable WorkItem tryLoadGroup(final @NotNull LoadMethod how, final int groupId) { + WorkItem item = this.dataItems.get(groupId); + if (how == LoadMethod.TRY_CACHE_ELSE_FETCH + && item instanceof CacheWorker.WorkItem cacheItem + && !cacheItem.isTryWithoutWrite + && !item.isLoaded()) { + this.dataItems.remove(groupId); + item = null; + } + + if (item == null) { + item = switch (how) { + case TRY_CACHE_ELSE_FETCH -> + this.groupStatuses[groupId] == GroupStatus.NOT_IN_CACHE + ? this.pageSource.enqueueLoad(this.pageId, groupId, (byte) 2) + : this.cacheWorker.tryRead(this.pageCache, groupId); + case READ_FROM_CACHE -> + this.cacheWorker.enqueueRead(this.pageCache, groupId); + }; + this.dataItems.put(groupId, item); + } + + if (!item.isLoaded()) { + return null; + } + + final byte[] data = item.getData(); + if (item instanceof CacheWorker.WorkItem cacheItem) { + try { + if (data == null || data.length <= 2) { + throw new RuntimeException(); + } + + CRC_32.reset(); + CRC_32.update(data, 0, data.length - 2); + if ((int) CRC_32.getValue() != this.index.groupCrcs[groupId]) { + throw new RuntimeException(); + } + if (this.index.groupWhirlpoolHashes != null && this.index.groupWhirlpoolHashes[groupId] != null) { + Whirlpool.checkHash(data, 0, data.length - 2, this.index.groupWhirlpoolHashes[groupId]); + } + final int var12 = ((data[data.length - 2] & 255) << 8) + (data[data.length - 1] & 255); + if (var12 != (this.index._v[groupId] & 0xffff)) { + throw new RuntimeException(); + } + + if (this.groupStatuses[groupId] != GroupStatus.IN_CACHE) { + this.groupStatuses[groupId] = GroupStatus.IN_CACHE; + } + if (!cacheItem.isTryWithoutWrite) { + this.dataItems.remove(groupId); + } + return cacheItem; + } catch (final Exception e) { + this.groupStatuses[groupId] = GroupStatus.NOT_IN_CACHE; + this.dataItems.remove(groupId); + if (cacheItem.isTryWithoutWrite) { + this.dataItems.put(groupId, this.pageSource.enqueueLoad(this.pageId, groupId, (byte) 2)); + } + return null; + } + } else { + if (data == null || data.length <= 2) { + throw new RuntimeException(); + } + + CRC_32.reset(); + CRC_32.update(data, 0, data.length - 2); + if ((int) CRC_32.getValue() != this.index.groupCrcs[groupId]) { + throw new RuntimeException(); + } + if (this.index.groupWhirlpoolHashes != null && this.index.groupWhirlpoolHashes[groupId] != null) { + Whirlpool.checkHash(data, 0, data.length - 2, this.index.groupWhirlpoolHashes[groupId]); + } + + this.pageSource.failureCount = 0; + this.pageSource.errorCode = null; + data[data.length - 2] = (byte) (this.index._v[groupId] >>> 8); + data[data.length - 1] = (byte) this.index._v[groupId]; + this.cacheWorker.enqueueWrite(this.pageCache, groupId, data); + if (this.groupStatuses[groupId] != GroupStatus.IN_CACHE) { + this.groupStatuses[groupId] = GroupStatus.IN_CACHE; + } + + return item; + } + } + + private enum GroupStatus { + IN_CACHE, NOT_IN_CACHE + } + + private enum LoadMethod { + TRY_CACHE_ELSE_FETCH, READ_FROM_CACHE + } + + public abstract static sealed class WorkItem permits PageSource.WorkItem, CacheWorker.WorkItem { + private volatile boolean isLoaded = false; + + public abstract byte[] getData(); + public abstract int percentLoaded(); + + public final boolean isLoaded() { + return this.isLoaded; + } + + public final void setLoaded() { + this.isLoaded = true; + } + } +} diff --git a/src/main/java/funorb/cache/PageSource.java b/src/main/java/funorb/cache/PageSource.java new file mode 100644 index 0000000..31145e9 --- /dev/null +++ b/src/main/java/funorb/cache/PageSource.java @@ -0,0 +1,55 @@ +package funorb.cache; + +import funorb.io.Buffer; +import org.jetbrains.annotations.NotNull; + +/** + * A {@link PageSource} manages loading resource pages that aren’t yet in the cache. + */ +public abstract class PageSource { + public volatile int failureCount = 0; + public volatile ErrorCode errorCode = null; + + protected abstract void enqueue(@NotNull WorkItem item); + public abstract void closeDueToError(); + + public final WorkItem enqueueLoad(final int pageId, final int part, final byte extraBytes) { + final WorkItem item = new WorkItem(((long) pageId << 32) + (long) part); + item.extraBytes = extraBytes; + + this.enqueue(item); + return item; + } + + public static final class WorkItem extends PageLoader.WorkItem { + final long partId; + byte extraBytes; + int bytesReadSoFar; + Buffer buffer; + + private WorkItem(final long partId) { + this.partId = partId; + } + + @Override + public int percentLoaded() { + if (this.buffer == null) { + return 0; + } else { + return 100 * this.buffer.pos / (this.buffer.data.length - this.extraBytes); + } + } + + @Override + public byte[] getData() { + if (!this.isLoaded() || this.buffer.pos < this.buffer.data.length - this.extraBytes) { + throw new IllegalStateException("not yet loaded"); + } + return this.buffer.data; + } + } + + public enum ErrorCode { + PROTOCOL_ERROR, INTEGRITY_CHECK_FAILURE, UNKNOWN_CONNECTION_FAILURE, SERVER_CODE_51, SERVER_CODE_50 + } +} diff --git a/src/main/java/funorb/cache/RemotePageSource.java b/src/main/java/funorb/cache/RemotePageSource.java new file mode 100644 index 0000000..e1a8c33 --- /dev/null +++ b/src/main/java/funorb/cache/RemotePageSource.java @@ -0,0 +1,252 @@ +package funorb.cache; + +import funorb.io.Buffer; +import funorb.io.DuplexStream; +import funorb.shatteredplans.client.JagexApplet; +import funorb.util.PseudoMonotonicClock; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.ArrayDeque; +import java.util.Queue; + +public final class RemotePageSource extends PageSource { + private static final int QUEUE_CAPACITY = 20; + + private final Queue unsentItems = new ArrayDeque<>(QUEUE_CAPACITY); + private final Queue pendingItems = new ArrayDeque<>(QUEUE_CAPACITY); + private WorkItem current; + + private final Buffer c2sPacket = new Buffer(6); + private final Buffer s2cPacket = new Buffer(10); + + private DuplexStream serverConnection; + private int millisSinceLastReceivedData; + private long lastLoadTime; + + @Override + protected void enqueue(final @NotNull WorkItem item) { + if (this.isQueueFull()) { + throw new IllegalStateException("queue overflow"); + } + this.unsentItems.add(item); + } + + private boolean isQueueFull() { + return this.queueSize() >= QUEUE_CAPACITY; + } + + private int queueSize() { + return this.unsentItems.size() + this.pendingItems.size(); + } + + public void initializeServerConnection(final DuplexStream serverConnection) { + if (this.serverConnection != null) { + try { + this.serverConnection.close(); + } catch (final Exception e) {} + } + + this.serverConnection = serverConnection; + this.handshake1(); + this.handshake2(); + this.current = null; + this.s2cPacket.pos = 0; + + WorkItem item; + while ((item = this.pendingItems.poll()) != null) { + this.unsentItems.add(item); + } + + this.millisSinceLastReceivedData = 0; + this.lastLoadTime = PseudoMonotonicClock.currentTimeMillis(); + } + + public void close() { + if (this.serverConnection != null) { + this.serverConnection.close(); + } + } + + @Override + public void closeDueToError() { + try { + this.serverConnection.close(); + } catch (final Exception e) {} + + this.serverConnection = null; + this.errorCode = ErrorCode.INTEGRITY_CHECK_FAILURE; + //noinspection NonAtomicOperationOnVolatileField + ++this.failureCount; + } + + public boolean processWork() { + if (this.serverConnection != null) { + final long now = PseudoMonotonicClock.currentTimeMillis(); + int millisSinceLast = (int) (now - this.lastLoadTime); + this.lastLoadTime = now; + if (millisSinceLast > 200) { + millisSinceLast = 200; + } + + this.millisSinceLastReceivedData += millisSinceLast; + if (this.millisSinceLastReceivedData > JagexApplet.SERVER_TIMEOUT_MILLIS) { + this.serverConnection.close(); + this.serverConnection = null; + } + } + if (this.serverConnection == null) { + return this.queueSize() == 0; + } + + try { + this.serverConnection.pollForException(); + + WorkItem item; + while ((item = this.unsentItems.poll()) != null) { + this.c2sPacket.pos = 0; + this.c2sPacket.writeByte(0); + this.c2sPacket.writeI40(item.partId); + this.serverConnection.write(this.c2sPacket.data, this.c2sPacket.data.length); + this.pendingItems.add(item); + } + + for (int i = 0; i < 100; ++i) { + final int available = this.serverConnection.inputAvailable(); + if (available == 0) { + break; + } + + this.millisSinceLastReceivedData = 0; + final byte bytesNeeded; + if (this.current == null) { + bytesNeeded = 10; + } else if (this.current.bytesReadSoFar == 0) { + bytesNeeded = 1; + } else { + bytesNeeded = 0; + } + + if (bytesNeeded > 0) { + int bytesToRead = bytesNeeded - this.s2cPacket.pos; + if (available < bytesToRead) { + bytesToRead = available; + } + + this.serverConnection.read(this.s2cPacket.data, this.s2cPacket.pos, bytesToRead); + this.s2cPacket.pos += bytesToRead; + + if (this.s2cPacket.pos >= bytesNeeded) { + if (this.current == null) { + this.s2cPacket.pos = 0; + final int group = this.s2cPacket.readUByte(); + final int index = this.s2cPacket.readInt(); + final int var8 = this.s2cPacket.readUByte(); + final int var9 = this.s2cPacket.readInt(); + final int isHigh = var8 & 127; + final boolean priority = (var8 & 128) != 0; + final long groupAndIndex = ((long) group << 32) + (long) index; + if (!priority) { + throw new IOException(); + } + + final WorkItem var14 = this.pendingItems.stream() + .filter(entry -> entry.partId == groupAndIndex).findFirst() + .orElseThrow(IOException::new); + + final int headerSize = isHigh != 0 ? 9 : 5; + this.current = var14; + this.current.buffer = new Buffer(this.current.extraBytes + var9 + headerSize); + this.current.buffer.writeByte(isHigh); + this.current.buffer.writeInt(var9); + this.s2cPacket.pos = 0; + this.current.bytesReadSoFar = 10; + } else { + if (this.current.bytesReadSoFar != 0) { + throw new IOException(); + } + + if (this.s2cPacket.data[0] == -1) { + this.s2cPacket.pos = 0; + this.current.bytesReadSoFar = 1; + } else { + this.current = null; + } + } + } + } else { + final int bytesWanted = this.current.buffer.data.length - this.current.extraBytes; + int bytesToRead = 512 - this.current.bytesReadSoFar; + if (bytesToRead > bytesWanted - this.current.buffer.pos) { + bytesToRead = bytesWanted - this.current.buffer.pos; + } + + if (bytesToRead > available) { + bytesToRead = available; + } + + this.serverConnection.read(this.current.buffer.data, this.current.buffer.pos, bytesToRead); + + this.current.bytesReadSoFar += bytesToRead; + this.current.buffer.pos += bytesToRead; + if (this.current.buffer.pos == bytesWanted) { + this.pendingItems.remove(this.current); + this.current.setLoaded(); + this.current = null; + } else if (this.current.bytesReadSoFar == 512) { + this.current.bytesReadSoFar = 0; + } + } + } + return true; + } catch (final IOException e) { + this.serverConnection.close(); + this.serverConnection = null; + //noinspection NonAtomicOperationOnVolatileField + ++this.failureCount; + this.errorCode = ErrorCode.PROTOCOL_ERROR; + return this.queueSize() == 0; + } + } + + private void handshake1() { + if (this.serverConnection != null) { + try { + this.c2sPacket.pos = 0; + this.c2sPacket.writeByte(6); + this.c2sPacket.writeI24(3); + this.c2sPacket.writeShort(0); + this.serverConnection.write(this.c2sPacket.data, this.c2sPacket.data.length); + } catch (final IOException var5) { + try { + this.serverConnection.close(); + } catch (final Exception e) {} + + //noinspection NonAtomicOperationOnVolatileField + ++this.failureCount; + this.serverConnection = null; + this.errorCode = ErrorCode.PROTOCOL_ERROR; + } + } + } + + private void handshake2() { + if (this.serverConnection != null) { + try { + this.c2sPacket.pos = 0; + this.c2sPacket.writeByte(3); + this.c2sPacket.writeI40(0L); + this.serverConnection.write(this.c2sPacket.data, this.c2sPacket.data.length); + } catch (final IOException var6) { + try { + this.serverConnection.close(); + } catch (final Exception e) {} + + //noinspection NonAtomicOperationOnVolatileField + ++this.failureCount; + this.errorCode = ErrorCode.PROTOCOL_ERROR; + this.serverConnection = null; + } + } + } +} diff --git a/src/main/java/funorb/cache/ResourceDirectory.java b/src/main/java/funorb/cache/ResourceDirectory.java new file mode 100644 index 0000000..4615947 --- /dev/null +++ b/src/main/java/funorb/cache/ResourceDirectory.java @@ -0,0 +1,57 @@ +package funorb.cache; + +import funorb.Strings; + +public final class ResourceDirectory { + private final int[] data; + + public ResourceDirectory(final int[] var1) { + int var2 = 1; + while (var2 <= var1.length + (var1.length >> 1)) { + var2 <<= 1; + } + + this.data = new int[var2 + var2]; + + for (int var3 = 0; var3 < var2 + var2; ++var3) { + this.data[var3] = -1; + } + + for (int var3 = 0; var1.length > var3; var3++) { + int var4 = var1[var3] & (var2 - 1); + while (this.data[1 + var4 + var4] != -1) { + var4 = (var2 - 1) & (var4 + 1); + } + + this.data[var4 + var4] = var1[var3]; + this.data[1 + var4 + var4] = var3; + } + } + + private static int resourceKeyHash(final CharSequence key) { + int hash = 0; + for (int var4 = 0; var4 < key.length(); ++var4) { + hash = Strings.encode1252Char(key.charAt(var4)) + (hash << 5) - hash; + } + return hash; + } + + public int lookup(final String key) { + final int hash = resourceKeyHash(key.toLowerCase()); + final int var3 = (this.data.length / 2) - 1; + + int var4 = var3 & hash; + while (true) { + final int var5 = this.data[1 + var4 + var4]; + if (var5 == -1) { + return -1; + } + + if (this.data[var4 + var4] == hash) { + return var5; + } + + var4 = var4 + 1 & var3; + } + } +} diff --git a/src/main/java/funorb/cache/ResourceLoader.java b/src/main/java/funorb/cache/ResourceLoader.java new file mode 100644 index 0000000..c1c9233 --- /dev/null +++ b/src/main/java/funorb/cache/ResourceLoader.java @@ -0,0 +1,472 @@ +package funorb.cache; + +import funorb.io.Buffer; +import funorb.io.ByteContainer; +import funorb.io.DirectByteContainer; +import funorb.shatteredplans.CacheFiles; +import org.intellij.lang.annotations.MagicConstant; + +import java.io.IOException; + +public final class ResourceLoader { + public static ResourceLoader COMMON_STRINGS; + public static ResourceLoader COMMON_SPRITES; + public static ResourceLoader COMMON_FONTS; + public static ResourceLoader HUFFMAN_CODES; + public static ResourceLoader SHATTERED_PLANS_STRINGS_1; + public static ResourceLoader SHATTERED_PLANS_SPRITES; + public static ResourceLoader SHATTERED_PLANS_JPEGS; + public static ResourceLoader SHATTERED_PLANS_FONTS; + public static ResourceLoader SHATTERED_PLANS_SFX_1; + public static ResourceLoader SHATTERED_PLANS_SFX_2; + public static ResourceLoader SHATTERED_PLANS_MUSIC_1; + public static ResourceLoader SHATTERED_PLANS_MUSIC_2; + public static ResourceLoader SHATTERED_PLANS_STRINGS_2; + public static ResourceLoader QUICK_CHAT_DATA; + public static ResourceLoader JAGEX_LOGO_ANIMATION; + + @SuppressWarnings("WeakerAccess") + public static final class PageId { + public static final int COMMON_STRINGS = 0; + public static final int COMMON_SPRITES = 1; + public static final int COMMON_FONTS = 2; + public static final int HUFFMAN_CODES = 3; + public static final int SHATTERED_PLANS_STRINGS_1 = 4; + public static final int SHATTERED_PLANS_SPRITES = 5; + public static final int SHATTERED_PLANS_JPEGS = 6; + public static final int SHATTERED_PLANS_FONTS = 7; + public static final int SHATTERED_PLANS_SFX_1 = 8; + public static final int SHATTERED_PLANS_SFX_2 = 9; + public static final int SHATTERED_PLANS_MUSIC_1 = 10; + public static final int SHATTERED_PLANS_MUSIC_2 = 11; + public static final int SHATTERED_PLANS_STRINGS_2 = 12; + public static final int QUICK_CHAT_DATA = 13; + public static final int JAGEX_LOGO_ANIMATION = 14; + public static final int INDEX = 255; + } + + public static BufferedCacheFile bufferedCacheDat2; + public static BufferedCacheFile[] bufferedCacheFiles; + + private final PageLoader pageLoader; + public boolean releaseGroupsOnGet; + public boolean releaseItemsOnGet; + private Object[] loadedGroupData; + private Object[][] loadedItems; + private PageIndex index; + + private ResourceLoader(final PageLoader pageLoader, final boolean releaseItemsOnGet) { + this.releaseItemsOnGet = releaseItemsOnGet; + this.releaseGroupsOnGet = true; + this.pageLoader = pageLoader; + } + + public static ResourceLoader create(final MasterIndexLoader masterIndexLoader, + final CacheFiles cacheFiles, + @MagicConstant(valuesFromClass = PageId.class) final int pageId) { + return create(cacheFiles, masterIndexLoader, pageId, true); + } + + public static ResourceLoader create(final CacheFiles cacheFiles, + final MasterIndexLoader masterIndexLoader, + @MagicConstant(valuesFromClass = PageId.class) final int pageId, + final boolean releaseItemsOnGet) { + try { + BufferedPageCache masterIndexCache = null; + if (bufferedCacheDat2 == null) { + bufferedCacheDat2 = new BufferedCacheFile(cacheFiles.data, 5200); + masterIndexCache = new BufferedPageCache(PageId.INDEX, bufferedCacheDat2, new BufferedCacheFile(cacheFiles.masterIndex, 12000)); + } + + if (bufferedCacheFiles == null) { + bufferedCacheFiles = new BufferedCacheFile[cacheFiles.indexes.length]; + } + if (bufferedCacheFiles[pageId] == null) { + bufferedCacheFiles[pageId] = new BufferedCacheFile(cacheFiles.indexes[pageId], 12000); + } + final BufferedPageCache pageCache = new BufferedPageCache(pageId, bufferedCacheDat2, bufferedCacheFiles[pageId]); + + final PageLoader entry = masterIndexLoader.getPageLoader(pageId, masterIndexCache, pageCache); + return new ResourceLoader(entry, releaseItemsOnGet); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + + // + private static byte[] asBytes(final Object o) { + if (o == null) { + return null; + } else if (o instanceof byte[] bs) { + return bs; + } else if (o instanceof ByteContainer bc) { + return bc.toByteArray(); + } else { + throw new IllegalArgumentException(); + } + } + + private static Object questionablyOptimizeBytes(final byte[] bs) { + if (bs == null) { + return null; + } else if (bs.length <= 136) { + return bs; + } else { + final DirectByteContainer bc = new DirectByteContainer(); + bc.put(bs); + return bc; + } + } + // + + // + public synchronized boolean isIndexLoaded() { + if (this.index == null) { + this.index = this.pageLoader.tryGetOrCreateIndex(); + if (this.index == null) { + return false; + } + this.loadedGroupData = new Object[this.index.groupCount]; + this.loadedItems = new Object[this.index.groupCount][]; + } + return true; + } + + public synchronized int percentLoaded() { + if (!this.isIndexLoaded()) { + return 0; + } + + int loadedSoFar = 0; + int totalNeeded = 0; + for (int i = 0; i < this.loadedGroupData.length; ++i) { + if (this.index.itemCounts[i] > 0) { + loadedSoFar += this.percentLoaded(i); + totalNeeded += 100; + } + } + + if (totalNeeded == 0) { + return 100; + } else { + return loadedSoFar * 100 / totalNeeded; + } + } + public int percentLoaded(final String group) { + if (this.isIndexLoaded()) { + return this.percentLoaded(this.index.groupDirectory.lookup(group)); + } else { + return 0; + } + } + + public synchronized int percentLoaded(final int groupId) { + if (!this.hasGroup(groupId)) { + return 0; + } else if (this.loadedGroupData[groupId] == null) { + return this.pageLoader.percentLoaded(groupId); + } else { + return 100; + } + } + // + + // + public int groupCount() { + return this.isIndexLoaded() ? this.index.groupSizes.length : -1; + } + + public int itemCount(final int groupId) { + if (this.hasGroup(groupId)) { + return this.index.groupSizes[groupId]; + } else { + return 0; + } + } + + @SuppressWarnings("SameParameterValue") + public int lookupGroup(final String group) { + if (this.isIndexLoaded()) { + final int var3 = this.index.groupDirectory.lookup(group); + return this.hasGroup(var3) ? var3 : -1; + } else { + return -1; + } + } + + public int lookupItem(final int groupId, final String item) { + if (!this.hasGroup(groupId)) { + return -1; + } + final int itemId = this.index.itemDirectories[groupId].lookup(item); + if (!this.hasResource(groupId, itemId)) { + return -1; + } + return itemId; + } + + @SuppressWarnings({"BooleanMethodIsAlwaysInverted", "SameParameterValue"}) + public boolean hasGroup(final String groupName) { + return this.isIndexLoaded() && this.index.groupDirectory.lookup(groupName) >= 0; + } + + private synchronized boolean hasGroup(final int groupId) { + return this.isIndexLoaded() && groupId >= 0 && groupId < this.index.groupSizes.length && this.index.groupSizes[groupId] != 0; + } + + private synchronized boolean hasResource(final int groupId, final int itemId) { + return this.isIndexLoaded() && groupId >= 0 && itemId >= 0 && groupId < this.index.groupSizes.length && itemId < this.index.groupSizes[groupId]; + } + + @SuppressWarnings({"BooleanMethodIsAlwaysInverted", "SameParameterValue"}) + public boolean hasResource(final String group, final String item) { + if (this.isIndexLoaded()) { + final int groupId = this.index.groupDirectory.lookup(group); + if (groupId < 0) { + return false; + } else { + final int itemId = this.index.itemDirectories[groupId].lookup(item); + return itemId >= 0; + } + } else { + return false; + } + } + // + + // + public synchronized boolean loadAllGroups() { + if (!this.isIndexLoaded()) { + return false; + } + boolean allLoaded = true; + for (int i = 0; i < this.index.groupIndexes.length; ++i) { + final int j = this.index.groupIndexes[i]; + if (this.loadedGroupData[j] == null) { + this.doLoadGroupData(j); + if (this.loadedGroupData[j] == null) { + allLoaded = false; + } + } + } + return allLoaded; + } + + public boolean loadGroupData(final String group) { + if (this.isIndexLoaded()) { + return this.loadGroupData(this.index.groupDirectory.lookup(group)); + } else { + return false; + } + } + + private synchronized boolean loadGroupData(final int groupId) { + if (!this.hasGroup(groupId)) { + return false; + } else if (this.loadedGroupData[groupId] == null) { + this.doLoadGroupData(groupId); + return this.loadedGroupData[groupId] != null; + } else { + return true; + } + } + + @SuppressWarnings("SameParameterValue") + public void loadGroupDataForItem(final String group, final String item) { + if (this.isIndexLoaded()) { + final int groupId = this.index.groupDirectory.lookup(group); + if (this.hasGroup(groupId)) { + final int itemId = this.index.itemDirectories[groupId].lookup(item); + this.loadGroupDataForItem(groupId, itemId); + } + } + } + + public synchronized void loadGroupDataForItem(final int groupId, final int itemId) { + if (this.hasResource(groupId, itemId) && + (this.loadedItems[groupId] == null || this.loadedItems[groupId][itemId] == null) && + this.loadedGroupData[groupId] == null) { + this.doLoadGroupData(groupId); + } + } + + public synchronized byte[] getResource(final String group, final String item) { + if (!this.isIndexLoaded()) { + return null; + } + final int groupId = this.index.groupDirectory.lookup(group); + if (!this.hasGroup(groupId)) { + return null; + } + final int itemId = this.index.itemDirectories[groupId].lookup(item); + return this.getResource(groupId, itemId); + } + + public byte[] getResource(final int groupId, final int itemId) { + synchronized (this) { + if (!this.hasResource(groupId, itemId)) { + return null; + } + + byte[] data = null; + if (this.loadedItems[groupId] == null || this.loadedItems[groupId][itemId] == null) { + if (!this.tryLoadGroupItems(groupId)) { + this.doLoadGroupData(groupId); + if (!this.tryLoadGroupItems(groupId)) { + return null; + } + } + } + + if (this.loadedItems[groupId] == null) { + throw new RuntimeException(""); + } + + if (this.loadedItems[groupId][itemId] != null) { + data = asBytes(this.loadedItems[groupId][itemId]); + if (data == null) { + throw new RuntimeException(""); + } + } + + if (data != null) { + if (this.releaseItemsOnGet) { + this.loadedItems[groupId][itemId] = null; + if (this.index.groupSizes[groupId] == 1) { + this.loadedItems[groupId] = null; + } + } + } + + return data; + } + } + + public synchronized byte[] getSingletonResource(final int id) { + if (!this.isIndexLoaded()) { + return null; + } else if (this.index.groupSizes.length == 1) { + return this.getResource(0, id); + } else if (this.hasGroup(id)) { + if (this.index.groupSizes[id] == 1) { + return this.getResource(id, 0); + } else { + throw new RuntimeException(); + } + } else { + return null; + } + } + + private synchronized void doLoadGroupData(final int groupId) { + if (this.releaseGroupsOnGet) { + this.loadedGroupData[groupId] = this.pageLoader.tryGetLoadedData(groupId); + } else { + this.loadedGroupData[groupId] = questionablyOptimizeBytes(this.pageLoader.tryGetLoadedData(groupId)); + } + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + private synchronized boolean tryLoadGroupItems(final int groupId) { + if (!this.hasGroup(groupId)) { + return false; + } + if (this.loadedGroupData[groupId] == null) { + return false; + } + + final int itemCount = this.index.itemCounts[groupId]; + final int[] itemIdMap = this.index.itemIdMaps[groupId]; + if (this.loadedItems[groupId] == null) { + this.loadedItems[groupId] = new Object[this.index.groupSizes[groupId]]; + } + + final Object[] loadedItems = this.loadedItems[groupId]; + boolean alreadyLoaded = true; + for (int i = 0; i < itemCount; ++i) { + final int itemId; + if (itemIdMap == null) { + itemId = i; + } else { + itemId = itemIdMap[i]; + } + if (loadedItems[itemId] == null) { + alreadyLoaded = false; + break; + } + } + + if (!alreadyLoaded) { + final byte[] groupData = PageIndex.decompress(asBytes(this.loadedGroupData[groupId])); + if (this.releaseGroupsOnGet) { + this.loadedGroupData[groupId] = null; + } + + if (itemCount > 1) { + final int lastPos = groupData.length - 1; + final int itemBlocks = groupData[lastPos] & 255; + final int lengthsStartPos = lastPos - (4 * itemBlocks * itemCount); + final Buffer groupBuffer = new Buffer(groupData); + groupBuffer.pos = lengthsStartPos; + final int[] itemPosns = new int[itemCount]; + + for (int i = 0; i < itemBlocks; ++i) { + int var16 = 0; + for (int j = 0; j < itemCount; ++j) { + var16 += groupBuffer.readInt(); + itemPosns[j] += var16; + } + } + + final byte[][] itemData = new byte[itemCount][]; + + for (int i = 0; i < itemCount; ++i) { + itemData[i] = new byte[itemPosns[i]]; + itemPosns[i] = 0; + } + + groupBuffer.pos = lengthsStartPos; + int groupPos = 0; + for (int i = 0; i < itemBlocks; ++i) { + int len = 0; + for (int j = 0; j < itemCount; ++j) { + len += groupBuffer.readInt(); + System.arraycopy(groupData, groupPos, itemData[j], itemPosns[j], len); + itemPosns[j] += len; + groupPos += len; + } + } + + for (int i = 0; i < itemCount; ++i) { + final int itemId; + if (itemIdMap == null) { + itemId = i; + } else { + itemId = itemIdMap[i]; + } + + if (this.releaseItemsOnGet) { + loadedItems[itemId] = itemData[i]; + } else { + loadedItems[itemId] = questionablyOptimizeBytes(itemData[i]); + } + } + } else { + final int itemId; + if (itemIdMap == null) { + itemId = 0; + } else { + itemId = itemIdMap[0]; + } + + if (this.releaseItemsOnGet) { + loadedItems[itemId] = groupData; + } else { + loadedItems[itemId] = questionablyOptimizeBytes(groupData); + } + } + } + return true; + } + // +} diff --git a/src/main/java/funorb/client/AchievementRequest.java b/src/main/java/funorb/client/AchievementRequest.java new file mode 100644 index 0000000..0cf7d93 --- /dev/null +++ b/src/main/java/funorb/client/AchievementRequest.java @@ -0,0 +1,7 @@ +package funorb.client; + +public final class AchievementRequest { + public boolean areAchievementsOffline = true; + public boolean completed = false; + public int unlockedAchievementsBitmap; +} diff --git a/src/main/java/funorb/client/DisplayMode.java b/src/main/java/funorb/client/DisplayMode.java new file mode 100644 index 0000000..064c5e8 --- /dev/null +++ b/src/main/java/funorb/client/DisplayMode.java @@ -0,0 +1,7 @@ +package funorb.client; + +public final class DisplayMode { + public int height; + public int width; + public int bitDepth; +} diff --git a/src/main/java/funorb/client/EmailLoginCredentials.java b/src/main/java/funorb/client/EmailLoginCredentials.java new file mode 100644 index 0000000..9a72429 --- /dev/null +++ b/src/main/java/funorb/client/EmailLoginCredentials.java @@ -0,0 +1,36 @@ +package funorb.client; + +import funorb.client.LoginCredentials; +import funorb.io.Buffer; +import funorb.shatteredplans.client.AuthMode; +import funorb.shatteredplans.client.JagexApplet; + +public final class EmailLoginCredentials extends LoginCredentials { + private static final AuthMode emailAuthMode = new AuthMode(AuthMode.EMAIL); + private final String email; + private final String password; + + public EmailLoginCredentials(final String email, final String password) { + this.email = email; + this.password = password; + } + + public static boolean containsPassword(final String message) { + if (JagexApplet.lastLoginPassword == null) { + return false; + } else { + return message.toLowerCase().contains(JagexApplet.lastLoginPassword.toLowerCase()); + } + } + + @Override + public void writeToPacket(final Buffer packet) { + JagexApplet.loginPacket.writeNullBracketedString(this.email); + JagexApplet.loginPacket.writePasswordHash(this.password); + } + + @Override + public AuthMode getAuthMode() { + return emailAuthMode; + } +} diff --git a/src/main/java/funorb/client/GetProfileRequest.java b/src/main/java/funorb/client/GetProfileRequest.java new file mode 100644 index 0000000..260db67 --- /dev/null +++ b/src/main/java/funorb/client/GetProfileRequest.java @@ -0,0 +1,6 @@ +package funorb.client; + +public final class GetProfileRequest { + public byte[] data; + public boolean completed; +} diff --git a/src/main/java/funorb/client/JagexBaseApplet.java b/src/main/java/funorb/client/JagexBaseApplet.java new file mode 100644 index 0000000..16a5304 --- /dev/null +++ b/src/main/java/funorb/client/JagexBaseApplet.java @@ -0,0 +1,328 @@ +package funorb.client; + +import funorb.awt.CanvasScreenBuffer; +import funorb.awt.ImageProducerScreenBuffer; +import funorb.awt.ScreenBuffer; +import funorb.awt.ComponentCanvas; +import funorb.shatteredplans.client.FrameClock; +import funorb.shatteredplans.client.JagexApplet; +import funorb.shatteredplans.client.MessagePumpThread; +import funorb.util.PseudoMonotonicClock; + +import java.applet.Applet; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.Rectangle; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.awt.geom.AffineTransform; +import java.net.URL; + +public abstract class JagexBaseApplet extends Applet implements Runnable, FocusListener, WindowListener { + protected static final long[] recentFrameTimes = new long[32]; + protected static JagexBaseApplet instance; // we are a singleton + public static Canvas canvas; + protected static volatile boolean _ncc = false; + protected static boolean hadFocus; // honestly not quite sure how this differs from hasFocus + protected static FrameClock frameClock; + protected static int framesToAdvance; + public static int lastFrameScore = 0; // not entirely sure how the absolute value of this is supposed to be interpreted + protected static int[] _f; + public static volatile boolean _oqe = true; + private static volatile long _pvcm = 0L; + public static ScreenBuffer screenBuffer; + private static boolean isShutdown = false; + private static long shutdownTimestamp = 0L; + private static int recentFrameIndex = 0; + public int gameCrc; + public boolean didHandleError = false; + private volatile boolean hasFocus = true; + private int canvasSyncTimer = 0; + + protected JagexBaseApplet() {} + + public static JagexBaseApplet getInstance() { + return instance; + } + + public static int[] a612(final int[] var0) { + final int var1 = var0.length; + final int[] var2 = new int[var1]; + + int var3 = 0; + while (var3 < var1) { + var2[var0[var3]] = var3++; + } + + return var2; + } + + public static void maybeSleep(final long var0) { + if (var0 > 0L) { + try { + Thread.sleep(var0); + } catch (final InterruptedException var3) { + } + } + } + + private static ScreenBuffer initializeScreenBuffer(final Component canvas, final int width, final int height) { + try { + final ScreenBuffer sb = new CanvasScreenBuffer(); + sb.initialize(canvas, width, height); + return sb; + } catch (final Throwable e) { + final ImageProducerScreenBuffer sb = new ImageProducerScreenBuffer(); + sb.initialize(canvas, width, height); + return sb; + } + } + + public static AffineTransform getTransform(final Component canvas) { + final double scaleX = (double) canvas.getWidth() / JagexApplet.gameWidth; + final double scaleY = (double) canvas.getHeight() / JagexApplet.gameHeight; + final double scale = Math.min(scaleX, scaleY); + + final double offsetX = (canvas.getWidth() - (JagexApplet.gameWidth * scale)) / 2; + final double offsetY = (canvas.getHeight() - (JagexApplet.gameHeight * scale)) / 2; + + final AffineTransform transform = new AffineTransform(); + transform.translate(offsetX, offsetY); + transform.scale(scale, scale); + return transform; + } + + public static void paint(final Canvas canvas) { + try { + final Graphics2D graphics = (Graphics2D) canvas.getGraphics(); + graphics.transform(getTransform(canvas)); + screenBuffer.paint(graphics); + graphics.dispose(); + } catch (final Exception e) { + canvas.repaint(); + } + } + + @Override + public final void start() { + if (instance == this && !isShutdown) { + shutdownTimestamp = 0L; + } + } + + @Override + public final void windowActivated(final WindowEvent var1) { + } + + @Override + public final void stop() { + if (instance == this && !isShutdown) { + shutdownTimestamp = PseudoMonotonicClock.currentTimeMillis() + 4000L; + } + } + + @Override + public final void windowIconified(final WindowEvent var1) { + } + + @Override + public final void windowDeiconified(final WindowEvent var1) { + } + + protected abstract void tick(); + + protected abstract void render(); + + @Override + public final void update(final Graphics var1) { + this.paint(var1); + } + + @Override + public final void windowClosing(final WindowEvent var1) { + this.destroy(); + } + + @Override + public final void run() { + instance.setFocusCycleRoot(true); + + this.initializeCanvas(); + screenBuffer = initializeScreenBuffer(canvas, JagexApplet.gameWidth, JagexApplet.gameHeight); + this.initialize(); + frameClock = new FrameClock(); + + while (shutdownTimestamp == 0L || shutdownTimestamp > PseudoMonotonicClock.currentTimeMillis()) { + maybeSleep(frameClock.finishFrame()); + framesToAdvance = frameClock.advanceFrame(); + + for (int i = 0; i < framesToAdvance; ++i) { + synchronized (this) { + hadFocus = this.hasFocus; + } + this.tick(); + } + + this.syncAndRender(); + MessagePumpThread.instance.postEvent(canvas); + } + + this.performShutdown(true); + } + + @Override + public final void windowOpened(final WindowEvent var1) { + } + + @Override + public final String getParameter(final String var1) { + return super.getParameter(var1); + } + + @Override + public final void focusLost(final FocusEvent var1) { + this.hasFocus = false; + } + + @Override + public final void windowClosed(final WindowEvent var1) { + } + + @Override + public final synchronized void paint(final Graphics var1) { + if (instance == this && !isShutdown) { + _oqe = true; + if (PseudoMonotonicClock.currentTimeMillis() - _pvcm > 1000L) { + final Rectangle var2 = var1.getClipBounds(); + if (var2 == null || var2.width >= JagexApplet.gameWidth && var2.height >= JagexApplet.gameHeight) { + _ncc = true; + } + } + } + } + + @Override + public abstract void init(); + + public final void redirectToErrorPage(final String which) { + if (!this.didHandleError) { + this.didHandleError = true; + System.out.println("error_game_" + which); + + try { + throw new NullPointerException("no Applet#getWindow anymore"); + } catch (final Throwable var5) { + } + try { + this.getAppletContext().showDocument(new URL(this.getCodeBase(), "error_game_" + which + ".ws"), "_top"); + } catch (final Exception var4) { + } + } + } + + protected abstract void initialize(); + + private void syncAndRender() { + final long now = PseudoMonotonicClock.currentTimeMillis(); + final long lastFrameTime = recentFrameTimes[recentFrameIndex]; + recentFrameTimes[recentFrameIndex] = now; + recentFrameIndex = (recentFrameIndex + 1) % recentFrameTimes.length; + if (lastFrameTime != 0L && lastFrameTime < now) { + final int lastFrameDuration = (int) (now - lastFrameTime); + lastFrameScore = ((lastFrameDuration / 2) + 32000) / lastFrameDuration; + } + + if (--this.canvasSyncTimer <= 0) { + this.canvasSyncTimer = 50; + _oqe = true; + canvas.setSize(instance.getSize()); + canvas.setVisible(true); + canvas.setLocation(0, 0); + } + + this.render(); + } + + @Override + public final void destroy() { + if (this == instance && !isShutdown) { + shutdownTimestamp = PseudoMonotonicClock.currentTimeMillis(); + maybeSleep(5000L); + MessagePumpThread.instance = null; + this.performShutdown(false); + } + } + + private void performShutdown(final boolean isClean) { + synchronized (this) { + if (isShutdown) { + return; + } + + isShutdown = true; + } + + try { + this.shutdown(); + } catch (final Exception var8) { + } + + if (canvas != null) { + try { + canvas.removeFocusListener(this); + canvas.getParent().remove(canvas); + } catch (final Exception var7) { + } + } + + if (MessagePumpThread.instance != null) { + try { + MessagePumpThread.instance.shutdown(); + } catch (final Exception var6) { + } + } + + System.out.println("Shutdown complete - clean:" + isClean); + } + + @Override + public final void windowDeactivated(final WindowEvent var1) { + } + + @Override + public final void focusGained(final FocusEvent var1) { + this.hasFocus = true; + _oqe = true; + } + + protected abstract void shutdown(); + + protected final synchronized void initializeCanvas() { + if (canvas != null) { + canvas.removeFocusListener(this); + canvas.getParent().setBackground(Color.black); + canvas.getParent().remove(canvas); + } + + instance.setLayout(new GridLayout()); + canvas = new ComponentCanvas(this); + instance.add(canvas); + canvas.setVisible(true); + canvas.setLocation(0, 0); + canvas.addFocusListener(this); + canvas.requestFocus(); + + hadFocus = true; + this.hasFocus = true; + + _oqe = true; + _ncc = false; + _pvcm = PseudoMonotonicClock.currentTimeMillis(); + } +} diff --git a/src/main/java/funorb/client/LoginCredentials.java b/src/main/java/funorb/client/LoginCredentials.java new file mode 100644 index 0000000..4b501a2 --- /dev/null +++ b/src/main/java/funorb/client/LoginCredentials.java @@ -0,0 +1,13 @@ +package funorb.client; + +import funorb.io.Buffer; +import funorb.shatteredplans.client.AuthMode; +import org.jetbrains.annotations.Contract; + +public abstract class LoginCredentials { + @SuppressWarnings("SameParameterValue") + public abstract void writeToPacket(Buffer packet); + + @Contract(pure = true) + public abstract AuthMode getAuthMode(); +} diff --git a/src/main/java/funorb/client/LoginState.java b/src/main/java/funorb/client/LoginState.java new file mode 100644 index 0000000..cb04a80 --- /dev/null +++ b/src/main/java/funorb/client/LoginState.java @@ -0,0 +1,15 @@ +package funorb.client; + +public enum LoginState { + C1, + LOGGED_IN, + C3, + C4, + SERVER_HANDSHAKE_FAILED, + C6, + READY_TO_LOG_IN, + LOGIN_REQUEST_SUCCESSFUL, + LOGIN_REQUEST_SENT, + C10, + SERVER_HANDSHAKE_SUCCESS +} diff --git a/src/main/java/funorb/client/MenuInputState.java b/src/main/java/funorb/client/MenuInputState.java new file mode 100644 index 0000000..971a50f --- /dev/null +++ b/src/main/java/funorb/client/MenuInputState.java @@ -0,0 +1,129 @@ +package funorb.client; + +import funorb.awt.KeyState; +import funorb.awt.MouseState; +import funorb.shatteredplans.client.JagexApplet; + +public final class MenuInputState { + public int itemCount; + public int selectedItem = 0; + + private boolean isMouseSelection = false; + private int lastTypedKeyCode; + private int mouseButtonDown; + private int mouseButtonJustClicked; + private int mouseButtonJustClickedOrRepeated; + private int mouseClickRepeatCounter; + + public MenuInputState(final int itemCount) { + this.itemCount = itemCount; + } + + public void setSelectedItem(final int mouseItem, final int keyboardItem, final boolean isMouseSelection) { + this.mouseButtonDown = 0; + this.isMouseSelection = isMouseSelection; + if (this.isMouseSelection) { + this.selectedItem = mouseItem; + } else { + this.selectedItem = keyboardItem; + } + } + + public void processKeyInputVertical() { + this.processKeyInput(KeyState.Code.UP, KeyState.Code.DOWN); + } + + @SuppressWarnings("SameParameterValue") + private void processKeyInput(final int prevCode, final int nextCode) { + this.lastTypedKeyCode = 0; + this.mouseButtonJustClickedOrRepeated = 0; + this.mouseButtonJustClicked = 0; + + if (this.mouseButtonDown == 0) { + this.lastTypedKeyCode = JagexApplet.lastTypedKeyCode; + if (this.lastTypedKeyCode == prevCode) { + this.isMouseSelection = false; + if (this.selectedItem <= 0) { + this.selectedItem = this.itemCount; + } + --this.selectedItem; + } else if (this.lastTypedKeyCode == nextCode) { + this.isMouseSelection = false; + ++this.selectedItem; + if (this.selectedItem >= this.itemCount) { + this.selectedItem = 0; + } + } + } + } + + public boolean isHomeTyped() { + return this.lastTypedKeyCode == KeyState.Code.HOME; + } + + public boolean isEndTyped() { + return this.lastTypedKeyCode == KeyState.Code.END; + } + + public boolean isLeftTyped() { + return this.lastTypedKeyCode == KeyState.Code.LEFT; + } + + public boolean isRightTyped() { + return this.lastTypedKeyCode == KeyState.Code.RIGHT; + } + + public void processMouseInput(final int hoveredItem, final int clickedItem) { + if (hoveredItem >= this.itemCount) { + throw new IndexOutOfBoundsException("hovered item is not in range [0," + this.itemCount + "): " + hoveredItem); + } + if (clickedItem >= this.itemCount) { + throw new IndexOutOfBoundsException("clicked item is not in range [0," + this.itemCount + "): " + clickedItem); + } + + this.lastTypedKeyCode = 0; + this.mouseButtonJustClickedOrRepeated = 0; + this.mouseButtonJustClicked = 0; + if (JagexApplet.mouseButtonJustClicked != MouseState.Button.NONE) { + this.mouseClickRepeatCounter = 20; + this.selectedItem = clickedItem; + this.mouseButtonJustClicked = this.mouseButtonJustClickedOrRepeated = JagexApplet.mouseButtonJustClicked; + this.mouseButtonDown = JagexApplet.mouseButtonJustClicked; + this.isMouseSelection = true; + } + + if (this.mouseButtonDown != 0 && JagexApplet.mouseButtonDown != MouseState.Button.NONE) { + if (this.mouseClickRepeatCounter <= 0) { + this.mouseClickRepeatCounter = 4; + this.mouseButtonJustClickedOrRepeated = this.mouseButtonDown; + } + --this.mouseClickRepeatCounter; + } + + if (JagexApplet.mouseButtonJustClicked == MouseState.Button.NONE + && JagexApplet.mouseButtonDown == MouseState.Button.NONE) { + this.mouseButtonDown = 0; + } + + if (this.mouseButtonDown == 0 && (this.isMouseSelection || JagexApplet.mouseEventReceived)) { + if (hoveredItem >= 0) { + this.selectedItem = hoveredItem; + this.isMouseSelection = true; + } else if (this.isMouseSelection) { + this.selectedItem = -1; + } + } + } + + public boolean isMouseButtonDown() { + return this.mouseButtonDown != 0; + } + + public boolean isItemActive() { + return this.mouseButtonJustClicked != 0 || this.lastTypedKeyCode == KeyState.Code.ENTER || this.lastTypedKeyCode == KeyState.Code.SPACE; + } + + public boolean isItemActiveAllowRepeat() { + return this.mouseButtonJustClickedOrRepeated != 0 || this.lastTypedKeyCode == KeyState.Code.ENTER || this.lastTypedKeyCode == KeyState.Code.SPACE; + } +} diff --git a/src/main/java/funorb/client/RankingsRequest.java b/src/main/java/funorb/client/RankingsRequest.java new file mode 100644 index 0000000..17dd0a0 --- /dev/null +++ b/src/main/java/funorb/client/RankingsRequest.java @@ -0,0 +1,13 @@ +package funorb.client; + +public final class RankingsRequest { + public int[][] _m; + public String[][] _n; + public int _r; + public int _h; + public boolean _q; + public int _k; + public int _i; + public int _j; + public int _l; +} diff --git a/src/main/java/funorb/client/ReflectionRequest.java b/src/main/java/funorb/client/ReflectionRequest.java new file mode 100644 index 0000000..2479fc4 --- /dev/null +++ b/src/main/java/funorb/client/ReflectionRequest.java @@ -0,0 +1,125 @@ +package funorb.client; + +import funorb.io.CipheredBuffer; +import funorb.shatteredplans.client.MailboxMessage; +import funorb.shatteredplans.client.MessagePumpThread; + +import java.util.ArrayDeque; +import java.util.Queue; +import java.util.stream.IntStream; + +public final class ReflectionRequest { + public static Queue pending = new ArrayDeque<>(); + + public final int id; + public final int messageCount; + public final int[] types; + public final int[] statusCodes; + public final MailboxMessage[] fieldMessages; + public final int[] fieldValues; + public final MailboxMessage[] methodMessages; + public final byte[][][] serializedParams; + + private ReflectionRequest(final int id, final int messageCount) { + this.id = id; + this.messageCount = messageCount; + this.types = new int[this.messageCount]; + this.statusCodes = new int[this.messageCount]; + this.fieldMessages = new MailboxMessage[this.messageCount]; + this.fieldValues = new int[this.messageCount]; + this.methodMessages = new MailboxMessage[this.messageCount]; + this.serializedParams = new byte[this.messageCount][][]; + } + + public static void recieve(final MessagePumpThread messagePumpThread, @SuppressWarnings("SameParameterValue") final CipheredBuffer packet) { + final int messageCount = packet.readUByte(); + final int id = packet.readInt(); + final ReflectionRequest req = new ReflectionRequest(id, messageCount); + + for (int i = 0; i < req.messageCount; ++i) { + try { + final int type = packet.readUByte(); + if (type == 0 || type == 1 || type == 2) { + final String className = packet.readNullTerminatedString(); + final String fieldName = packet.readNullTerminatedString(); + final int fieldValue = type == 1 ? packet.readInt() : 0; + + req.types[i] = type; + req.fieldValues[i] = fieldValue; + req.fieldMessages[i] = messagePumpThread.sendGetDeclaredFieldMessage(classForName(className), fieldName); + } else if (type == 3 || type == 4) { + final String className = packet.readNullTerminatedString(); + final String methodName = packet.readNullTerminatedString(); + + final int var9 = packet.readUByte(); + final String[] paramTypeNames = IntStream.range(0, var9) + .mapToObj(j -> packet.readNullTerminatedString()) + .toArray(String[]::new); + + final byte[][] serializedObjects = new byte[var9][]; + if (type == 3) { + for (int j = 0; j < var9; ++j) { + final int objectLen = packet.readInt(); + serializedObjects[j] = new byte[objectLen]; + packet.readBytes(serializedObjects[j], objectLen); + } + } + + req.types[i] = type; + final Class[] paramTypes = new Class[var9]; + for (int var13 = 0; var13 < var9; ++var13) { + paramTypes[var13] = classForName(paramTypeNames[var13]); + } + + req.methodMessages[i] = messagePumpThread.sendGetDeclaredMethodMessage(classForName(className), methodName, paramTypes); + req.serializedParams[i] = serializedObjects; + } + } catch (final ClassNotFoundException e) { + req.statusCodes[i] = Status.CLASS_NOT_FOUND; + } catch (final SecurityException e) { + req.statusCodes[i] = Status.SECURITY_EXCEPTION; + } catch (final NullPointerException e) { + req.statusCodes[i] = Status.NULL_POINTER_EXCEPTION; + } catch (final Exception e) { + req.statusCodes[i] = Status.OTHER_EXCEPTION; + } catch (final Throwable e) { + req.statusCodes[i] = Status.OTHER_THROWABLE; + } + } + + pending.add(req); + } + + private static Class classForName(final String name) throws ClassNotFoundException { + return switch (name) { + case "B" -> Byte.TYPE; + case "C" -> Character.TYPE; + case "D" -> Double.TYPE; + case "F" -> Float.TYPE; + case "I" -> Integer.TYPE; + case "J" -> Long.TYPE; + case "S" -> Short.TYPE; + case "Z" -> Boolean.TYPE; + default -> Class.forName(name); + }; + } + + public static final class Type { + public static final int STATIC_FIELD_GET = 0; + public static final int STATIC_FIELD_SET = 1; + public static final int FIELD_GET_MODIFIERS = 2; + public static final int METHOD_INVOKE = 3; + public static final int METHOD_GET_MODIFIERS = 4; + + } + + @SuppressWarnings("WeakerAccess") + public static final class Status { + public static final int OK = 0; + public static final int CLASS_NOT_FOUND = -1; + public static final int SECURITY_EXCEPTION = -2; + public static final int NULL_POINTER_EXCEPTION = -3; + public static final int OTHER_EXCEPTION = -4; + public static final int OTHER_THROWABLE = -5; + } +} diff --git a/src/main/java/funorb/client/SetProfileRequest.java b/src/main/java/funorb/client/SetProfileRequest.java new file mode 100644 index 0000000..9b599e2 --- /dev/null +++ b/src/main/java/funorb/client/SetProfileRequest.java @@ -0,0 +1,10 @@ +package funorb.client; + +public final class SetProfileRequest { + public final byte[] data; + public int digest; + + public SetProfileRequest(final byte[] data) { + this.data = data; + } +} diff --git a/src/main/java/funorb/client/TemplateDictionary.java b/src/main/java/funorb/client/TemplateDictionary.java new file mode 100644 index 0000000..805d945 --- /dev/null +++ b/src/main/java/funorb/client/TemplateDictionary.java @@ -0,0 +1,84 @@ +package funorb.client; + +public final class TemplateDictionary { + private final TemplateDictionary next; + private Entry entry; + + public TemplateDictionary() { + this(null); + } + + public TemplateDictionary(final TemplateDictionary var1) { + this.next = var1; + } + + private String get(final String key) { + for (Entry entry = this.entry; entry != null; entry = entry.next) { + if (key.equals(entry.key)) { + return entry.value; + } + } + if (this.next == null) { + return null; + } else { + return this.next.get(key); + } + } + + public void put(final String key, final String value) { + for (Entry entry = this.entry; entry != null; entry = entry.next) { + if (key.equals(entry.key)) { + entry.value = value; + return; + } + } + this.entry = new Entry(key, value, this.entry); + } + + public String expand(final String template) { + final StringBuilder var3 = new StringBuilder(template.length()); + int var4 = 0; + + final int var5 = template.length(); + + while (var4 < var5) { + int var6 = template.indexOf("<%", var4); + if (var6 >= 0) { + var3.append(template, var4, var6); + var4 = var6; + var6 = template.indexOf(">", var6 + 2); + if (var6 >= 0) { + final String var7 = template.substring(var4 + 2, var6); + final String var8 = this.get(var7); + if (var8 != null) { + var3.append(var8); + } + + var4 = 1 + var6; + continue; + } + + var3.append(template, var4, var5); + break; + } + + var3.append(template, var4, var5); + break; + } + + return var3.toString(); + } + + @SuppressWarnings("WeakerAccess") + private static final class Entry { + public final Entry next; + public final String key; + public String value; + + public Entry(final String key, final String value, final Entry next) { + this.key = key; + this.value = value; + this.next = next; + } + } +} diff --git a/src/main/java/funorb/client/UserIdLoginCredentials.java b/src/main/java/funorb/client/UserIdLoginCredentials.java new file mode 100644 index 0000000..685c65f --- /dev/null +++ b/src/main/java/funorb/client/UserIdLoginCredentials.java @@ -0,0 +1,74 @@ +package funorb.client; + +import funorb.io.Buffer; +import funorb.shatteredplans.client.AuthMode; + +public final class UserIdLoginCredentials extends LoginCredentials { + private static final long USER_ID_LIMIT = 6582952005840035281L; + private static final AuthMode userIdAuthMode = new AuthMode(AuthMode.USER_ID); + + private final long userId; + private final String password; + + public UserIdLoginCredentials(final long userId, final String password) { + this.userId = userId; + this.password = password; + } + + public static long encodeUsername(final CharSequence username) { + long userId = 0L; + for (int i = 0; i < username.length(); ++i) { + userId *= 37L; + final char c = username.charAt(i); + if (c >= 'A' && c <= 'Z') { + userId += 1 - (65 - c); + } else if (c >= 'a' && c <= 'z') { + userId += 1 + c - 97; + } else if (c >= '0' && c <= '9') { + userId += c + 27 - 48; + } + + if (userId >= USER_ID_LIMIT / 37L) { + break; + } + } + + while (userId != 0L && userId % 37L == 0L) { + userId /= 37L; + } + + return userId; + } + + public static String decodeUsername(long userId) { + assert userId >= 0 && userId < USER_ID_LIMIT; + final StringBuilder sb = new StringBuilder(12); + while (userId != 0) { + final int x = (int) (userId % 37); + if (x == 0) { + sb.append(' '); + } else if (x < 27) { + if (userId / 37 % 37 == 0) { + sb.append((char) ('A' + (x - 1))); + } else { + sb.append((char) ('a' + (x - 1))); + } + } else { + sb.append((char) ('0' + (x - 27))); + } + userId /= 37; + } + return sb.reverse().toString(); + } + + @Override + public AuthMode getAuthMode() { + return userIdAuthMode; + } + + @Override + public void writeToPacket(final Buffer packet) { + packet.writeLong(this.userId); + packet.writePasswordHash(this.password); + } +} diff --git a/src/main/java/funorb/client/e_.java b/src/main/java/funorb/client/e_.java new file mode 100644 index 0000000..b8bfc81 --- /dev/null +++ b/src/main/java/funorb/client/e_.java @@ -0,0 +1,31 @@ +package funorb.client; + +public final class e_ { + private String _c; + private boolean _a; + + public e_(final String var1) { + this(var1, false); + } + + public e_(final String var1, final boolean var2) { + this._c = var1; + this._a = var2; + if (this._c == null) { + this._c = ""; + } + + if (this._c.length() == 0) { + this._a = false; + } + + } + + public String a983() { + return this._c; + } + + public boolean a154() { + return this._a; + } +} diff --git a/src/main/java/funorb/client/intro/JagexLogoIntroAnimation.java b/src/main/java/funorb/client/intro/JagexLogoIntroAnimation.java new file mode 100644 index 0000000..1da8c30 --- /dev/null +++ b/src/main/java/funorb/client/intro/JagexLogoIntroAnimation.java @@ -0,0 +1,1325 @@ +package funorb.client.intro; + +import funorb.audio.fd_; +import funorb.cache.ResourceLoader; +import funorb.client.JagexBaseApplet; +import funorb.graphics.Drawing; +import funorb.graphics.Sprite; +import funorb.graphics.mq_; +import funorb.io.CipheredBuffer; +import funorb.shatteredplans.client.JagexApplet; +import funorb.util.BitMath; + +import java.util.stream.IntStream; + +public final class JagexLogoIntroAnimation { + private static final Sprite _rfh = new Sprite(270, 70); + private static final Sprite _ini = new Sprite(540, 140); + private static sr_[] _vcd; + private static int[] _ucw; + private static hc_[] _wca; + private static Sprite _qaq; + private static Sprite _akz; + private static int[][] _faZ; + + private static int jagexIntroAnimationFrame; + private static int width; + private static int height; + private static int halfWidth; + private static int halfHeight; + + private static final int[] _uoh = new int[128]; + private static final int[] _gdb = new int[1024]; + private static final int[] _noc = new int[8192]; + private static final int[] _hko = new int[8192]; + private static final int[] _fmc = new int[8192]; + private static final int[] _cff = new int[8192]; + private static final int[] _hei = new int[8192]; + private static final int[] _pmC = new int[8192]; + private static final int[] _jlM = new int[16384]; + + private static int[] _h = new int[1024]; + private static int _qje = 0; + private static int[] _mwsa; + + // + public static void load(final ResourceLoader loader) { + load1(loader); + load2(loader); + load3(loader); + load4(); + load5(); + + jagexIntroAnimationFrame = -55; + } + + private static void load1(final ResourceLoader loader) { + fd_.b604(loader.getResource("headers.packvorbis", "")); + final fd_ var2 = fd_.a968(loader, "jagex logo2.packvorbis", ""); + assert var2 != null; + var2.b720(); + } + + private static void load2(final ResourceLoader loader) { + final CipheredBuffer var2 = new CipheredBuffer(loader.getResource("logo.fo3d", "")); + final int var3 = var2.readUByte(); + var2.m150(); + _wca = a477ip(var2); + _vcd = new sr_[var3]; + _faZ = new int[var3][]; + for (int var4 = 0; var3 > var4; ++var4) { + _vcd[var4] = a523ec(var2); + } + + var2.i423(); + + for (int var4 = 0; var3 > var4; ++var4) { + final sr_ var5 = _vcd[var4]; + var5.a050(); + var5.a487(); + final int[] var6 = new int[]{var5._O + var5._k >> 1, var5._j + var5._t >> 1, var5._E + var5._r >> 1}; + _faZ[var4] = var6; + var5.a115(-var6[2], -var6[0], -var6[1]); + } + } + + private static void load3(final ResourceLoader loader) { + final Sprite var1 = new Sprite(loader.getResource("final_frame.jpg", ""), JagexBaseApplet.canvas); + final int var2 = var1.width; + final int var3 = var1.height; + Drawing.withLocalContext(() -> { + _qaq = new Sprite(var2, 3 * var3 / 4); + _qaq.installForDrawing(); + var1.c093(0, 0); + _akz = new Sprite(var2, -_qaq.height + var3); + _akz.installForDrawing(); + var1.c093(0, -_qaq.height); + _akz.y = _qaq.height; + }); + } + + private static void load4() { + c797wn(); + _ucw = new int[260]; + + int var0; + for (var0 = 0; var0 < 256; ++var0) { + final double var1 = 15.0D; + _ucw[var0] = (int) (255.0D * Math.pow((float) var0 / 256.0F, var1)); + } + + for (var0 = 256; var0 < _ucw.length; ++var0) { + _ucw[var0] = 255; + } + } + + private static void load5() { + final Sprite var0 = new Sprite(540, 140); + var0.withInstalledForDrawingUsingOffsets(() -> { + c797wn(); + Drawing.clear(); + jagexIntroAnimationFrame = 0; + e150gq(); + final Sprite var1 = var0.copy(); + + for (int var2 = 0; var2 < 15; ++var2) { + var1.e326(-2, -2, Drawing.WHITE); + Drawing.b669(4, 4, 540, 140); + } + + _rfh.installForDrawing(); + var0.d093(0, 0); + }); + } + // + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public static boolean isFinished() { + return JagexApplet.DEBUG_MODE || jagexIntroAnimationFrame > 250; + } + + public static void tick() { + ++jagexIntroAnimationFrame; + } + + public static void draw() { + if (jagexIntroAnimationFrame >= 0) { + final int var2 = 185; + final int var3 = 205; + int var4 = 256; + if (jagexIntroAnimationFrame < 75) { + var4 = (jagexIntroAnimationFrame << 8) / 75; + } + + if (jagexIntroAnimationFrame > 200) { + var4 = (-jagexIntroAnimationFrame + 250 << 8) / 50; + } + + final int finalVar4 = var4; + _ini.withInstalledForDrawingUsingOffsets(() -> { + c797wn(); + Drawing.clear(); + e150gq(); + if (finalVar4 < 256) { + Drawing.fillRect(0, 0, Drawing.width, Drawing.height, 0, 256 - finalVar4); + } + }); + + if (jagexIntroAnimationFrame < 150) { + _ini.d093(var2, var3); + } else { + _qaq.draw(200, 215, var4); + } + + final int var5 = jagexIntroAnimationFrame - 125; + int var6; + if (var5 > 0 && var5 < 50) { + if (var5 < 20) { + var6 = var5 * 256 / 20; + _rfh.drawAdd(var2, var3, var6); + } else if (var5 >= 30) { + var6 = 256 * (50 - var5) / 20; + _rfh.drawAdd(var2, var3, var6); + } else { + _rfh.drawAdd(var2, var3, 256); + } + } + + final int i = jagexIntroAnimationFrame - 140; + if (i > 0) { + var6 = 256; + if (i < 20) { + var6 = i * 256 / 20; + } + + _akz.draw(200, 215, var6 * var4 >> 8); + } + } + } + + private static void c797wn() { + width = Drawing.right - Drawing.left; + height = Drawing.bottom - Drawing.top; + halfWidth = width / 2; + halfHeight = height / 2; + if (_h.length < height) { + _h = new int[BitMath.nextLowestPowerOf2(height)]; + } + + int var4 = Drawing.top * Drawing.width + Drawing.left; + + for (int var5 = 0; var5 < height; ++var5) { + _h[var5] = var4; + var4 += Drawing.width; + } + } + + private static void a806pe(final int[] var2, final sr_ var4) { + final int var7 = (var2[0] << 16) >> 5; + final int var8 = (var2[1] * 0xffff0000) >> 5; + final int var9 = ((var2[2] - 0xffffe030) << 16) >> 16; + final int var10 = (var2[3] << 14) >> 14; + final int var11 = var2[4] * 0xffffc000 >> 14; + final int var12 = (var2[5] << 14) >> 14; + final int var13 = (var2[6] << 14) >> 14; + final int var14 = var2[7] * 0xffffc000 >> 14; + final int var15 = (var2[8] << 14) >> 14; + final int var16 = (var2[9] << 14) >> 14; + final int var17 = var2[10] * 0xffffc000 >> 14; + final int var18 = (var2[11] << 14) >> 14; + + int var5 = Integer.MAX_VALUE; + int var6 = Integer.MIN_VALUE; + for (int i = 0; i < var4._x; ++i) { + final short var31 = var4._w[i]; + final short var32 = var4._z[i]; + final short var33 = var4._f[i]; + final int var25 = (var10 * var31 + var32 * var13 + var33 * var16 >> 5) + var7; + final int var26 = var8 + (var32 * var14 + var31 * var11 + var33 * var17 >> 5); + final int var27 = var9 + (var32 * var15 + var31 * var12 + var33 * var18 >> 16); + if (var27 < 50) { + _noc[i] = Integer.MIN_VALUE; + } else { + _pmC[i] = var25 / var27 + halfWidth; + _hei[i] = var26 / var27 + halfHeight; + if (var5 > var27) { + var5 = var27; + } + + if (var27 > var6) { + var6 = var27; + } + + _noc[i] = var27; + } + } + + final int i4 = var2[3]; + final int i5 = var2[4]; + final int i6 = var2[5]; + final int i7 = var2[6]; + final int i8 = var2[7]; + final int i9 = var2[8]; + final int i10 = var2[9]; + final int i11 = var2[10]; + final int i12 = var2[11]; + for (int i = 0; i < var4._e && i < _fmc.length; ++i) { + final short var28 = var4._I[i]; + final short var29 = var4._y[i]; + final short var30 = var4._v[i]; + _fmc[i] = var30 * i10 + var29 * i7 + i4 * var28 >> 16; + _cff[i] = var30 * i11 + var28 * i5 + i8 * var29 >> 16; + _hko[i] = i6 * var28 - (-(i9 * var29) - var30 * i12) >> 16; + } + + a787ej(var4, var5, var6); + } + + private static void a087er(final int var0, final int var1, final int var3, final int var4, final sr_ var5, final int var6, final int var7) { + if (var5._p != null && var5._o > 1) { + final byte[] var9 = var5._p; + a181eb(var9); + } else { + a423kc(); + } + + final int[] var8 = new int[var5._e]; + final int[] var40 = new int[var5._e]; + final int[] var10 = _fmc; + final int[] var11 = _cff; + final int[] var12 = _hko; + + int var13; + int var14; + for (var13 = 0; var5._e > var13; ++var13) { + var14 = var10[var13] * var0 + var11[var13] * var3 + var12[var13] * var7 >> 8; + if (var14 < 0) { + var14 = -var14; + } + + var14 = var14 >= 128 ? 256 : var14 + 128; + int var15 = var10[var13] * var6 - (-(var1 * var11[var13]) - var12[var13] * var4) >> 8; + var15 = _ucw[var15 >= 0 ? var15 : -var15]; + var14 = (-var15 + 256) * var14 >>> 8; + var8[var13] = var14; + var40[var13] = var15; + } + + for (var13 = 0; var13 < _qje; ++var13) { + var14 = _jlM[var13]; + final short var41 = var5._s[var14]; + final short var16 = var5._i[var14]; + final short var17 = var5._B[var14]; + final short var18 = var5._M[var14] < _fmc.length ? var5._M[var14] : -1; + final short var19 = var5._P[var14] < _fmc.length ? var5._P[var14] : -1; + final short var20 = var5._n[var14] >= _fmc.length ? -1 : var5._n[var14]; + final hc_ var21 = _wca != null && var5._b != null && var14 < var5._b.length && var5._b[var14] != -1 && _wca.length > var5._b[var14] ? _wca[var5._b[var14]] : null; + final int var22 = _pmC[var41]; + final int var23 = _hei[var41]; + final int var24 = _pmC[var16]; + final int var25 = _hei[var16]; + final int var26 = _pmC[var17]; + final int var27 = _hei[var17]; + final int var28; + final int var29; + final int var30; + final int var31; + final int var32; + int var33; + if (var18 == var19 && var20 == var19) { + var28 = var8[var18]; + var29 = var40[var18]; + var30 = var21 != null ? var21._a : 8355711; + var31 = 16711935 & var30; + var32 = '\uff00' & var30; + var33 = var28 * var31 >>> 8 & 268370175 | var28 * var32 >>> 8 & 989921024; + var33 += 65793 * var29; + a676oo(var23, var26, var27, var25, var33 >> 1 & 8355711, var24, var22); + } else { + var28 = var8[var18]; + var29 = var8[var19]; + var30 = var8[var20]; + var31 = var40[var18]; + var32 = var40[var19]; + var33 = var40[var20]; + final int var34 = var21 != null ? var21._a : 8355711; + final int var35 = 16711935 & var34; + final int var36 = var34 & '\uff00'; + int var37 = (-16711905 & var35 * var28) >>> 8 | var28 * var36 >>> 8 & -1845428480; + int var38 = (16711777 & var36 * var29) >>> 8 | var29 * var35 >>> 8 & 1459552511; + var37 += 65793 * var31; + int var39 = var30 * var36 >>> 8 & -570360064 | (-16711872 & var30 * var35) >>> 8; + var38 += 65793 * var32; + var39 += var33 * 65793; + a101bf((var38 & 'u') >> 8, var37 & 255, var39 >> 16, var37 >> 8 & 255, var37 >> 16, var26, var22, var39 & 255, var25, 255 & var38, var27, (var39 & '\ufff3') >> 8, var24, var38 >> 16, var23); + } + } + + } + + private static void a495lr(final int var0, final int var1, final int var3, int var4, final int[] var5, final int var6, final int var7, final int var8, final int var9, final int var10, final int var11, final int var12, final int var13, final int var14, final int var15, final int var16) { + if (var8 >= 0 && var4 < height) { + if (var3 >= 0 || var0 >= 0 || var14 >= 0) { + if (width > var3 || width > var0 || var14 < width) { + final int var34 = -var4 + var8; + int var17; + int var18; + int var19; + int var20; + int var21; + int var22; + int var23; + int var24; + int var25; + int var26; + int var27; + int var28; + int var29; + int var30; + int var31; + int var32; + final boolean var33; + int var35; + int var37; + int var38; + int var39; + int var40; + if (var15 == var4) { + if (var8 == var4) { + var27 = 0; + var32 = 0; + var18 = var0 << 16; + var29 = var10; + var23 = 0; + var17 = var3 << 16; + var24 = 0; + var19 = 0; + var21 = var9; + var25 = var16; + var28 = 0; + var26 = var11; + var31 = 0; + var30 = var1; + var20 = 0; + var22 = var7; + } else { + var35 = -var15 + var8; + if (var0 <= var3) { + var28 = (var12 - var16 << 16) / var34; + var30 = var10 << 16; + var18 = var3 << 16; + var29 = var1 << 16; + var31 = (var13 - var1 << 16) / var35; + var17 = var0 << 16; + var20 = (-var3 + var14 << 16) / var34; + var32 = (-var10 + var13 << 16) / var34; + var25 = var11 << 16; + var27 = (-var11 + var12 << 16) / var35; + var21 = var7 << 16; + var24 = (var6 - var9 << 16) / var34; + var19 = (var14 - var0 << 16) / var35; + var22 = var9 << 16; + var26 = var16 << 16; + var23 = (var6 - var7 << 16) / var35; + } else { + var23 = (-var9 + var6 << 16) / var34; + var32 = (-var1 + var13 << 16) / var35; + var27 = (var12 - var16 << 16) / var34; + var29 = var10 << 16; + var30 = var1 << 16; + var22 = var7 << 16; + var31 = (var13 - var10 << 16) / var34; + var24 = (var6 - var7 << 16) / var35; + var28 = (var12 - var11 << 16) / var35; + var26 = var11 << 16; + var25 = var16 << 16; + var18 = var0 << 16; + var17 = var3 << 16; + var21 = var9 << 16; + var19 = (var14 - var3 << 16) / var34; + var20 = (var14 - var0 << 16) / var35; + } + } + + if (var4 < 0) { + var4 = Math.min(-var4, 0); + var22 += var24 * var4; + var17 += var19 * var4; + var25 += var27 * var4; + var18 += var4 * var20; + var29 += var31 * var4; + var30 += var4 * var32; + var26 += var4 * var28; + var21 += var23 * var4; + var4 = 0; + } + + } else { + var25 = var26 = var16 << 16; + var17 = var18 = var3 << 16; + var21 = var22 = var9 << 16; + var29 = var30 = var10 << 16; + var35 = var15 - var4; + var20 = (var14 - var3 << 16) / var34; + var19 = (-var3 + var0 << 16) / var35; + if (var20 <= var19) { + final int var36 = var19; + var19 = var20; + var20 = var36; + var27 = (var12 - var16 << 16) / var34; + var32 = (var1 - var10 << 16) / var35; + var24 = (-var9 + var7 << 16) / var35; + var31 = (var13 - var10 << 16) / var34; + var23 = (-var9 + var6 << 16) / var34; + var33 = true; + var28 = (var11 - var16 << 16) / var35; + } else { + var27 = (var11 - var16 << 16) / var35; + var32 = (var13 - var10 << 16) / var34; + var28 = (-var16 + var12 << 16) / var34; + var31 = (-var10 + var1 << 16) / var35; + var33 = false; + var23 = (var7 - var9 << 16) / var35; + var24 = (-var9 + var6 << 16) / var34; + } + + label146: + { + if (var4 < 0) { + if (var15 < 0) { + var4 = var15 - var4; + var17 += var19 * var4; + var30 += var4 * var32; + var29 += var4 * var31; + var22 += var4 * var24; + var26 += var28 * var4; + var18 += var4 * var20; + var21 += var23 * var4; + var25 += var27 * var4; + var4 = var15; + break label146; + } + + var4 = -var4; + var29 += var4 * var31; + var26 += var28 * var4; + var21 += var4 * var23; + var25 += var4 * var27; + var22 += var4 * var24; + var18 += var4 * var20; + var30 += var32 * var4; + var17 += var19 * var4; + var4 = 0; + } + + for (int var36 = _h[var4]; var4 < var15; var30 += var32) { + var37 = var17 >> 16; + if (var37 < width) { + var38 = (var18 >> 16) - (var17 >> 16); + if (var38 != 0) { + var39 = (var22 - var21) / var38; + var40 = (var26 - var25) / var38; + final int var41 = (var30 - var29) / var38; + if (width <= var38 + var37) { + var38 = width - 1 - var37; + } + + if (var37 >= 0) { + a575jg(var38, var29, var37 + var36, var40, var25, var21, var41, var5, var39); + } else { + a575jg(var38 + var37, var29 - var37 * var41, var36, var40, -(var40 * var37) + var25, -(var37 * var39) + var21, var41, var5, var39); + } + } else if (var37 >= 0) { + a575jg(var38, var29, var37 + var36, 0, var25, var21, 0, var5, 0); + } + } + + ++var4; + if (height <= var4) { + return; + } + + var21 += var23; + var29 += var31; + var17 += var19; + var18 += var20; + var22 += var24; + var25 += var27; + var36 += Drawing.width; + var26 += var28; + } + } + + final int var36 = -var15 + var8; + if (var36 == 0) { + var19 = 0; + var28 = 0; + var31 = 0; + var23 = 0; + var27 = 0; + var24 = 0; + var20 = 0; + var32 = 0; + } else { + var37 = var14 << 16; + var38 = var6 << 16; + var39 = var12 << 16; + if (var33) { + var30 = var1 << 16; + var22 = var7 << 16; + var26 = var11 << 16; + var18 = var0 << 16; + } else { + var21 = var7 << 16; + var29 = var1 << 16; + var17 = var0 << 16; + var25 = var11 << 16; + } + + var40 = var13 << 16; + var19 = (var37 - var17) / var36; + var27 = (-var25 + var39) / var36; + var23 = (-var21 + var38) / var36; + var28 = (-var26 + var39) / var36; + var31 = (var40 - var29) / var36; + var32 = (-var30 + var40) / var36; + var24 = (-var22 + var38) / var36; + var20 = (-var18 + var37) / var36; + } + } + + if (var4 < 0) { + var4 = -var4; + var26 += var4 * var28; + var30 += var4 * var32; + var29 += var4 * var31; + var18 += var20 * var4; + var25 += var4 * var27; + var22 += var24 * var4; + var17 += var19 * var4; + var21 += var4 * var23; + var4 = 0; + } + + for (var35 = _h[var4]; var4 < var8; var30 += var32) { + final int var36 = var17 >> 16; + if (var36 < width) { + var37 = -(var17 >> 16) + (var18 >> 16); + if (var37 != 0) { + var38 = (-var21 + var22) / var37; + var39 = (-var25 + var26) / var37; + var40 = (-var29 + var30) / var37; + if (var37 + var36 >= width) { + var37 = -var36 + (width - 1); + } + + if (var36 < 0) { + a575jg(var37 + var36, -(var36 * var40) + var29, var35, var39, var25 - var36 * var39, var21 - var36 * var38, var40, var5, var38); + } else { + a575jg(var37, var29, var36 + var35, var39, var25, var21, var40, var5, var38); + } + } else if (var36 >= 0) { + a575jg(var37, var29, var36 + var35, 0, var25, var21, 0, var5, 0); + } + } + + ++var4; + if (var4 >= height) { + return; + } + + var25 += var27; + var21 += var23; + var26 += var28; + var35 += Drawing.width; + var22 += var24; + var17 += var19; + var18 += var20; + var29 += var31; + } + } + } + } + } + + private static void a575jg(int var0, int var1, int var2, final int var3, int var4, int var5, final int var6, final int[] var7, final int var8) { + while (true) { + --var0; + if (var0 < 0) { + return; + } + + final int var14 = (var7[var2] & 16711422) >> 1; + var7[var2] = var14 + ((33471547 & var1) >> 17) - (-(65280 & var4 >> 9) - ((33423360 & var5) >> 1)); + ++var2; + var1 += var6; + var5 += var8; + var4 += var3; + } + } + + private static void a451oo(final int var0, final int var1, final int var3, final int var4, final int var5, final int[] var6, int var7, final int var8) { + if (var8 >= 0 && var7 < height) { + if (var3 >= 0 || var1 >= 0 || var0 >= 0) { + if (var3 < width || var1 < width || width > var0) { + final int var14 = -var7 + var8; + int var9; + int var10; + int var11; + int var12; + final boolean var13; + int var15; + int var16; + int var17; + if (var5 == var7) { + if (var7 == var8) { + var9 = var3 << 16; + var11 = 0; + var12 = 0; + var10 = var1 << 16; + } else { + var15 = var8 - var5; + if (var3 < var1) { + var10 = var1 << 16; + var12 = (var0 - var1 << 16) / var15; + var9 = var3 << 16; + var11 = (var0 - var3 << 16) / var14; + } else { + var10 = var3 << 16; + var12 = (var0 - var3 << 16) / var14; + var11 = (-var1 + var0 << 16) / var15; + var9 = var1 << 16; + } + } + + if (var7 < 0) { + var7 = Math.min(-var7, -var7 + var5); + var9 += var7 * var11; + var10 += var12 * var7; + var7 = 0; + } + + } else { + var9 = var10 = var3 << 16; + var15 = var5 - var7; + var11 = (var1 - var3 << 16) / var15; + var12 = (-var3 + var0 << 16) / var14; + if (var11 >= var12) { + var13 = true; + var16 = var11; + var11 = var12; + var12 = var16; + } else { + var13 = false; + } + + label143: + { + if (var7 < 0) { + if (var5 < 0) { + var7 = -var7 + var5; + var10 += var12 * var7; + var9 += var7 * var11; + var7 = var5; + break label143; + } + + var7 = -var7; + var9 += var7 * var11; + var10 += var12 * var7; + var7 = 0; + } + + for (var16 = _h[var7]; var7 < var5; var9 += var11) { + var17 = var9 >> 16; + if (width > var17) { + int var18 = -(var9 >> 16) + (var10 >> 16); + if (var18 == 0) { + if (var17 >= 0) { + a743dp(var17 + var16, var6, var4, 0); + } + } else { + if (width <= var17 + var18) { + var18 = width - 1 - var17; + } + + if (var17 < 0) { + a743dp(var16, var6, var4, var17 + var18); + } else { + a743dp(var17 + var16, var6, var4, var18); + } + } + } + + ++var7; + if (height <= var7) { + return; + } + + var10 += var12; + var16 += Drawing.width; + } + } + + var16 = var8 - var5; + if (var16 == 0) { + var11 = 0; + var12 = 0; + } else { + if (var13) { + var10 = var1 << 16; + } else { + var9 = var1 << 16; + } + + var17 = var0 << 16; + var11 = (var17 - var9) / var16; + var12 = (var17 - var10) / var16; + } + } + + if (var7 < 0) { + var7 = -var7; + var9 += var7 * var11; + var10 += var12 * var7; + var7 = 0; + } + + for (var15 = _h[var7]; var8 > var7; var9 += var11) { + var16 = var9 >> 16; + if (var16 < width) { + var17 = (var10 >> 16) - (var9 >> 16); + if (var17 != 0) { + if (var16 + var17 >= width) { + var17 = width - 1 - var16; + } + + if (var16 >= 0) { + a743dp(var16 + var15, var6, var4, var17); + } else { + a743dp(var15, var6, var4, var17 + var16); + } + } else if (var16 >= 0) { + a743dp(var15 + var16, var6, var4, var17); + } + } + + ++var7; + if (var7 >= height) { + return; + } + + var15 += Drawing.width; + var10 += var12; + } + + } + } + } + } + + private static void a743dp(int var0, final int[] var1, final int var2, int var3) { + while (true) { + --var3; + if (var3 < 0) { + return; + } + + var1[var0] = var2 + ((var1[var0] & 16711422) >> 1); + ++var0; + } + } + + private static void a787ej(final sr_ var2, final int var3, final int var4) { + final int var5 = BitMath.lastSet((var4 - var3) * 3); + final int var6 = 3 * var3; + g423ah(); + final int var7 = var5 - 10; + if (var2._o > 0 && var2._p != null) { + e150mf(); + } + + _qje = 0; + + int var8; + label72: + for (var8 = 0; var8 < var2._u; ++var8) { + final short var9 = var2._s[var8]; + final short var10 = var2._i[var8]; + final short var11 = var2._B[var8]; + final int var12; + final int var13; + final int var14; + final int var15; + int var16; + int var17; + + var12 = _noc[var9]; + if (var12 != Integer.MIN_VALUE) { + var13 = _noc[var10]; + if (var13 != Integer.MIN_VALUE) { + var14 = _noc[var11]; + if (var14 != Integer.MIN_VALUE) { + var15 = var13 + var12 - (-var14 + var6); + var16 = -(var7 < 0 ? var15 << -var7 : var15 >> var7) - 1 + _gdb.length; + + for (var17 = _gdb[var16]; var17 >> 4 != 0; var17 = _gdb[var16]) { + --var16; + if (var16 < 0) { + System.err.println("Out of range!"); + continue label72; + } + } + + final int var18 = (var16 << 4) + var17; + _jlM[var18] = var8; + _gdb[var16] = var17 + 1; + if (var2._o > 0 && var2._p != null) { + _uoh[var2._p[var8]]++; + } + + ++_qje; + } + } + } + } + + if (var2._o > 0 && var2._p != null) { + var8 = 0; + + for (int var19 = 0; _uoh.length > var19; ++var19) { + final int var20 = _uoh[var19]; + _uoh[var19] = var8; + var8 += var20; + } + } + + } + + private static void g423ah() { + final int[] var0 = _gdb; + int var1 = 0; + + for (final int var3 = var0.length; var3 > var1; var0[var1++] = 0) { + var0[var1++] = 0; + var0[var1++] = 0; + var0[var1++] = 0; + var0[var1++] = 0; + var0[var1++] = 0; + var0[var1++] = 0; + var0[var1++] = 0; + } + } + + private static void e150mf() { + final int[] var1 = _uoh; + + int var2 = 0; + + for (final int var3 = var1.length; var3 > var2; var1[var2++] = 0) { + var1[var2++] = 0; + var1[var2++] = 0; + var1[var2++] = 0; + var1[var2++] = 0; + var1[var2++] = 0; + var1[var2++] = 0; + var1[var2++] = 0; + } + + } + + private static void a101bf(final int var0, final int var1, final int var2, final int var3, final int var4, final int var5, final int var6, final int var7, final int var8, final int var9, final int var10, final int var11, final int var12, final int var13, final int var14) { + if (var14 >= var8) { + if (var10 <= var14) { + if (var8 >= var10) { + a495lr(var12, var9, var5, var10, Drawing.screenBuffer, var4, var13, var14, var2, var7, var0, var3, var1, var6, var8, var11); + } else { + a495lr(var5, var7, var12, var8, Drawing.screenBuffer, var4, var2, var14, var13, var9, var11, var3, var1, var6, var10, var0); + } + } else { + a495lr(var6, var1, var12, var8, Drawing.screenBuffer, var2, var4, var10, var13, var9, var3, var11, var7, var5, var14, var0); + } + } else if (var8 < var10) { + a495lr(var12, var9, var6, var14, Drawing.screenBuffer, var2, var13, var10, var4, var1, var0, var11, var7, var5, var8, var3); + } else if (var14 >= var10) { + a495lr(var6, var1, var5, var10, Drawing.screenBuffer, var13, var4, var8, var2, var7, var3, var0, var9, var12, var14, var11); + } else { + a495lr(var5, var7, var6, var14, Drawing.screenBuffer, var13, var2, var8, var4, var1, var11, var0, var9, var12, var10, var3); + } + } + + private static void a181eb(final byte[] var2) { + for (int var4 = 0; var4 < _gdb.length; ++var4) { + int var1 = _gdb[var4]; + int var10004; + int var0; + for (int var5 = var4 << 4; var1-- != 0; _jlM[var10004] = var0) { + var0 = _jlM[var5++]; + final byte var10002 = var2[var0]; + var10004 = _uoh[var2[var0]]; + _uoh[var10002] = _uoh[var2[var0]] + 1; + } + } + } + + private static void a423kc() { + int var1 = _gdb[0]; + for (int var2 = 1; var2 < _gdb.length; ++var2) { + final int var3 = _gdb[var2]; + System.arraycopy(_jlM, var2 << 4, _jlM, var1, var3); + var1 += var3; + } + } + + private static void a676oo(final int var0, final int var1, final int var2, final int var3, final int var4, final int var5, final int var7) { + if (var0 < var3) { + if (var3 < var2) { + a451oo(var1, var5, var7, var4, var3, Drawing.screenBuffer, var0, var2); + } else if (var0 < var2) { + a451oo(var5, var1, var7, var4, var2, Drawing.screenBuffer, var0, var3); + } else { + a451oo(var5, var7, var1, var4, var0, Drawing.screenBuffer, var2, var3); + } + } else if (var0 < var2) { + a451oo(var1, var7, var5, var4, var0, Drawing.screenBuffer, var3, var2); + } else if (var3 >= var2) { + a451oo(var7, var5, var1, var4, var3, Drawing.screenBuffer, var2, var0); + } else { + a451oo(var7, var1, var5, var4, var2, Drawing.screenBuffer, var3, var0); + } + + } + + private static void e150gq() { + final int var1 = _vcd.length; + final int[] var2 = new int[var1]; + + for (int var3 = 0; var3 < var1; ++var3) { + final sr_ var4 = _vcd[var3]; + var4.a487(); + a093ec(var3); + final int var5 = var4._O + var4._k >> 1; + final int var6 = var4._j + var4._t >> 1; + final int var7 = var4._r + var4._E >> 1; + final int var11 = (_mwsa[5] << 14) >> 14; + final int var12 = (_mwsa[8] << 14) >> 14; + final int var13 = (_mwsa[11] << 14) >> 14; + var2[var3] = var13 * var7 + var11 * var5 + var6 * var12 >> 16; + } + + final int var19 = 0; + final int var6 = jagexIntroAnimationFrame << 4; + int var7 = 0; + int var8 = mq_.a353je(var6) >> 8; + int var9 = mq_.b080mq(var6) >> 8; + if (JagexApplet.mouseX != -1 && JagexApplet.mouseY != -1) { + var7 = JagexApplet.mouseX - 320; + var9 = -128; + var8 = 240 - JagexApplet.mouseY; + } + + final double var20 = 256.0D / Math.sqrt(var9 * var9 + var7 * var7 + var8 * var8); + var7 = (int) ((double) var7 * var20); + var8 = (int) ((double) var8 * var20); + var9 = (int) ((double) var9 * var20); + int var12 = var7; + int var13 = var8 - var19; + int var14 = var9 - 0x100; + final double v = 256.0D / Math.sqrt(var14 * var14 + var13 * var13 + var12 * var12); + var12 = (int) ((double) var12 * v); + var14 = (int) ((double) var14 * v); + var13 = (int) ((double) var13 * v); + + int var16; + for (int var15 = 0; _vcd.length > var15; ++var15) { + var16 = 0; + + for (int var17 = 1; var17 < _vcd.length; ++var17) { + if (var2[var17] > var2[var16]) { + var16 = var17; + } + } + + var2[var16] = Integer.MIN_VALUE; + final sr_ var21 = _vcd[var16]; + a093ec(var16); + + for (int var18 = 0; var18 < 3; ++var18) { + final int[] var10000 = _mwsa; + var10000[var18] += _faZ[var15][var18]; + } + + a806pe(_mwsa, var21); + a087er(var7, var13, var8, var14, var21, var12, var9); + } + } + + private static void a093ec(final int var0) { + int var1 = 0; + int var2 = jagexIntroAnimationFrame; + if (var2 >= 5) { + if (var2 < 105) { + var1 = ((var2 << 14) - 0xa000) / 220; + } else if (var2 < 120) { + var2 = 120 - var2; + var1 = 8192 - var2 * var2 * 8192 / 3300; + } + } else { + var1 = 8192 * var2 * var2 / 1100; + } + + byte var3 = 1; + byte var4 = 0; + if (var0 == 1) { + var4 = 1; + } + + if (var0 == 3) { + var3 = -1; + } + + if (var0 == 4) { + var4 = 1; + } + + if (var0 == 5) { + var4 = 1; + var3 = -1; + } + + if (var0 == 6) { + var4 = -1; + } + + if (var0 == 7 || var0 == 8) { + var4 = -1; + var3 = -1; + } + + if (var0 == 11) { + var3 = -1; + } + + if (var0 == 12) { + var4 = -1; + var3 = -1; + } + + if (var0 == 13) { + var4 = -1; + } + + if (var0 == 14) { + var3 = -1; + var4 = 1; + } + + if (var0 == 15) { + var4 = 1; + } + + _mwsa = mq_.a977mq(var3 * var1, var4 * var1); + } + + private static hc_[] a477ip(final CipheredBuffer var0) { + final int var1 = var0.b543(8); + if (var1 <= 0) { + final int var2 = var0.b543(12); + final hc_[] var3 = new hc_[var2]; + + for (int var4 = 0; var2 > var4; ++var4) { + if (a523ng(var0)) { + final hc_ var5 = new hc_(); + var0.b543(24); + var0.b543(24); + var5._a = var0.b543(24); + var0.b543(9); + var0.b543(12); + var0.b543(12); + var0.b543(12); + var3[var4] = var5; + } else { + final int var6 = var0.b543(a080a(var4 - 1)); + var3[var4] = var3[var6]; + } + } + + return var3; + } else { + return null; + } + } + + private static byte[] a382ec(final CipheredBuffer var1, byte[] var2) { + final int var3 = var1.b543(16); + if (var3 == 0) { + return null; + } else { + if (var2 == null || var2.length != var3) { + var2 = new byte[var3]; + } + + final int var4 = var1.b543(3); + final byte var5 = (byte) var1.b543(8); + int var6; + if (var4 <= 0) { + for (var6 = 0; var6 < var3; ++var6) { + var2[var6] = var5; + } + } else { + for (var6 = 0; var6 < var3; ++var6) { + var2[var6] = (byte) (var5 + var1.b543(var4)); + } + } + + return var2; + } + } + + private static sr_ a523ec(final CipheredBuffer var0) { + final int var1 = var0.b543(8); + if (var1 <= 0) { + final boolean var2 = a523ng(var0); + final boolean var3 = a523ng(var0); + final sr_ var4 = new sr_(); + var4._x = (short) var0.b543(16); + var4._w = a704tm(var0, var4._w); + var4._z = a704tm(var0, var4._z); + var4._f = a704tm(var0, var4._f); + var4._u = (short) var0.b543(16); + var4._s = a704tm(var0, var4._s); + var4._i = a704tm(var0, var4._i); + var4._B = a704tm(var0, var4._B); + if (var2) { + var4._e = (short) var0.b543(16); + var4._I = a704tm(var0, var4._I); + var4._y = a704tm(var0, var4._y); + var4._v = a704tm(var0, var4._v); + var4._M = a704tm(var0, var4._M); + var4._P = a704tm(var0, var4._P); + var4._n = a704tm(var0, var4._n); + } + + if (var3) { + var0.b543(16); + var4._C = a704tm(var0, var4._C); + var4._g = a704tm(var0, var4._g); + var4._L = a704tm(var0, var4._L); + var4._J = a704tm(var0, var4._J); + var4._G = a704tm(var0, var4._G); + } + + if (a523ng(var0)) { + var4._b = a704tm(var0, var4._b); + } + + if (a523ng(var0)) { + var4._p = a382ec(var0, var4._p); + assert var4._p != null; + final int var6 = IntStream.range(0, var4._p.length).map(var7 -> (var4._p[var7] & 255)).max().orElse(0); + + if (var6 == 0) { + var4._p = null; + } else { + var4._o = (byte) (1 + var6); + } + } + + return var4; + } else { + throw new IllegalStateException("" + var1); + } + } + + private static boolean a523ng(final CipheredBuffer var0) { + return var0.b543(1) == 1; + } + + private static short[] a704tm(final CipheredBuffer var1, short[] var3) { + final int var4 = var1.b543(16); + if (var4 == 0) { + return null; + } else { + if (var3 == null || var3.length != var4) { + var3 = new short[var4]; + } + + final int var5 = var1.b543(4); + final short var6 = (short) var1.b543(16); + int var7; + if (var5 <= 0) { + for (var7 = 0; var7 < var4; ++var7) { + var3[var7] = var6; + } + } else { + for (var7 = 0; var7 < var4; ++var7) { + var3[var7] = (short) (var1.b543(var5) + var6); + } + } + + return var3; + } + } + + private static int a080a(int var0) { + if (var0 == 0) { + return 0; + } else { + int var1; + if (var0 <= 0) { + var1 = 2; + if (var0 < -65536) { + var1 += 16; + var0 >>= 16; + } + + if (var0 < -256) { + var1 += 8; + var0 >>= 8; + } + + if (var0 < -16) { + var1 += 4; + var0 >>= 4; + } + + if (var0 < -4) { + var1 += 2; + var0 >>= 2; + } + + if (var0 < -2) { + ++var1; + } + + } else { + var1 = 1; + if (var0 > 65535) { + var1 += 16; + var0 >>= 16; + } + + if (var0 > 255) { + var0 >>= 8; + var1 += 8; + } + + if (var0 > 15) { + var0 >>= 4; + var1 += 4; + } + + if (var0 > 3) { + var1 += 2; + var0 >>= 2; + } + + if (var0 > 1) { + ++var1; + } + + } + return var1; + } + } +} diff --git a/src/main/java/funorb/client/intro/hc_.java b/src/main/java/funorb/client/intro/hc_.java new file mode 100644 index 0000000..c58195b --- /dev/null +++ b/src/main/java/funorb/client/intro/hc_.java @@ -0,0 +1,5 @@ +package funorb.client.intro; + +public final class hc_ { + public int _a; +} diff --git a/src/main/java/funorb/client/intro/sr_.java b/src/main/java/funorb/client/intro/sr_.java new file mode 100644 index 0000000..43d0fdc --- /dev/null +++ b/src/main/java/funorb/client/intro/sr_.java @@ -0,0 +1,110 @@ +package funorb.client.intro; + +public final class sr_ { + public byte _o = 0; + public short[] _P; + public short[] _g; + public short[] _M; + public short[] _b; + public short[] _C; + public short[] _w; + public short[] _s; + public short[] _v; + public short[] _y; + public short _x; + public short[] _I; + public short[] _z; + public byte[] _p; + public short[] _B; + public short _u; + public short[] _i; + public int _k; + public int _E; + public short[] _f; + public int _t; + public int _j; + public int _r; + public short _e; + public short[] _L; + public short[] _J; + public short[] _n; + public short[] _G; + public int _O; + private boolean _d = false; + + private void a150() { + this._d = false; + } + + public void a115(final int var1, final int var2, final int var3) { + for (int var5 = 0; this._x > var5; ++var5) { + final short[] var10000 = this._w; + var10000[var5] = (short) (var10000[var5] + var2); + final short[] z = this._z; + z[var5] = (short) (z[var5] + var3); + final short[] f = this._f; + f[var5] = (short) (f[var5] + var1); + } + + this.a150(); + } + + public void a487() { + if (!this._d) { + this._d = true; + short var2 = 32767; + short var3 = 32767; + short var4 = 32767; + short var5 = -32768; + short var6 = -32768; + short var7 = -32768; + + for (int var8 = 0; var8 < this._x; ++var8) { + final short var9 = this._w[var8]; + final short var10 = this._z[var8]; + if (var2 > var9) { + var2 = var9; + } + + if (var9 > var5) { + var5 = var9; + } + + if (var6 < var10) { + var6 = var10; + } + + if (var10 < var3) { + var3 = var10; + } + + final short var11 = this._f[var8]; + if (var4 > var11) { + var4 = var11; + } + + if (var7 < var11) { + var7 = var11; + } + } + + this._k = var2; + this._t = var6; + this._j = var3; + this._E = var4; + this._O = var5; + this._r = var7; + } + } + + public void a050() { + for (int var6 = 0; var6 < this._x; ++var6) { + this._w[var6] = (short) (6 * this._w[var6]); + this._z[var6] = (short) (this._z[var6] * 6); + this._f[var6] = (short) (this._f[var6] * 6); + } + + this.a150(); + + } +} diff --git a/src/main/java/funorb/client/li_.java b/src/main/java/funorb/client/li_.java new file mode 100644 index 0000000..deaec4e --- /dev/null +++ b/src/main/java/funorb/client/li_.java @@ -0,0 +1,15 @@ +package funorb.client; + +import java.io.IOException; +import java.net.Socket; + +public abstract class li_ { + protected int _a; + protected String _f; + + protected final Socket a693() throws IOException { + return new Socket(this._f, this._a); + } + + public abstract Socket b693() throws IOException; +} diff --git a/src/main/java/funorb/client/lobby/ActionButton.java b/src/main/java/funorb/client/lobby/ActionButton.java new file mode 100644 index 0000000..a86e510 --- /dev/null +++ b/src/main/java/funorb/client/lobby/ActionButton.java @@ -0,0 +1,88 @@ +package funorb.client.lobby; + +import funorb.graphics.Font; +import funorb.graphics.Sprite; + +public final class ActionButton extends Component> { + public Component _Bb; + private Component _Db; + + public ActionButton(final Component attrsSrc, final Component tooltipAttrsSrc, final Sprite var6, final String tooltipLabel) { + super(attrsSrc); + if (var6 != null) { + this._Db = new Component<>(null); + this._Db.sprite = var6; + this.addChild(this._Db); + } + + if (tooltipLabel != null) { + this._Bb = new Component<>(tooltipAttrsSrc, tooltipLabel); + this.addChild(this._Bb); + } + + this.recursivelySet_H(); + } + + private void a326(final int var2, int var3) { + int var4 = -var2; + + if (this._Db != null) { + var4 = this._Db.e474(); + } + + int var5 = -var2; + if (this._Bb != null) { + var5 = this._Bb.a353(-var3 + (-var2 - var3) + (this.width - var4)); + } + + int var6 = var3 + var4 + var3 - (-var2 - var5); + if (this.width < var6) { + var5 += this.width - var6; + var6 = this.width; + } + + if (this.textAlignment == Font.HorizontalAlignment.CENTER) { + var3 += (this.width - var6) / 2; + } + + if (this.textAlignment == Font.HorizontalAlignment.RIGHT) { + var3 += this.width - var6; + } + + if (this._Db != null) { + this._Db.setBounds(var3, 0, var4, this.height); + this._Db.verticalAlignment = this.verticalAlignment; + } + + if (this._Bb != null) { + this._Bb.setBounds(var3 + var4 + var2, 0, var5, this.height); + if (this._Db == null) { + this._Bb.textAlignment = this.textAlignment; + } else { + this._Bb.textAlignment = Font.HorizontalAlignment.LEFT; + } + + this._Bb.verticalAlignment = this.verticalAlignment; + } + + } + + public void a370(final int var2, final int var3, final int var4, final int var5, final int var6, final int var7) { + this.setBounds(var7, var3, var6, var2); + this.a326(var5, var4); + } + + public int a776(final int var1, final int var3) { + int var4 = -var1; + int var5 = -var1; + if (this._Db != null) { + var4 = this._Db.e474(); + } + + if (this._Bb != null) { + var5 = this._Bb.e474(); + } + + return var5 + var4 + var3 + var1 + var3; + } +} diff --git a/src/main/java/funorb/client/lobby/AddOrRemovePlayerPopup.java b/src/main/java/funorb/client/lobby/AddOrRemovePlayerPopup.java new file mode 100644 index 0000000..2489f7c --- /dev/null +++ b/src/main/java/funorb/client/lobby/AddOrRemovePlayerPopup.java @@ -0,0 +1,190 @@ +package funorb.client.lobby; + +import funorb.Strings; +import funorb.awt.KeyState; +import funorb.awt.MouseState; +import funorb.shatteredplans.client.JagexApplet; +import org.intellij.lang.annotations.MagicConstant; + +public final class AddOrRemovePlayerPopup extends Component> { + public static AddOrRemovePlayerPopup openInstance; + @MagicConstant(valuesFromClass = Action.class) + public static int action = Action.NONE; + private final Component _zb; + private final StringBuilder _Db; + private int _Ab = 0; + + public AddOrRemovePlayerPopup(final int x, final int y, final int var3, final int var4, final String labelText, final Component attrsSrc, final Component labelAttrsSrc, final Component var8) { + super(attrsSrc); + final Component label = new Component<>(labelAttrsSrc, labelText); + this.addChild(label); + this._zb = new Component<>(var8); + this._zb.textColor = 16764006; + this.addChild(this._zb); + this._zb._u = "|"; + this._Db = new StringBuilder(12); + final int var9 = label.e474(); + label.setBounds(5, 3, var9, Component.LABEL_HEIGHT); + this._zb.setBounds(5, Component.LABEL_HEIGHT + 3, var9, Component.LABEL_HEIGHT); + final int var10 = 5 + var9 + 5; + final int var11 = 3 + Component.LABEL_HEIGHT * 2 + 3; + final int var12 = PopupMenu.positionPopupX(x, var3, var10); + final int var13 = PopupMenu.positionPopupY(y, var4, var11); + this.setBounds(var12, var13, var10, var11); + } + + private static void setStringBuilderLengthAndFillWithSpaces(final StringBuilder sb, final int newLen) { + final int oldLen = sb.length(); + sb.setLength(newLen); + + for (int i = oldLen; i < newLen; ++i) { + sb.setCharAt(i, ' '); + } + } + + public static void removeLastCharacterFromStringBuilder(final StringBuilder sb) { + setStringBuilderLengthAndFillWithSpaces(sb, sb.length() - 1); + } + + private static boolean a412tmg(final char var0, final CharSequence var1) { + if (Strings.isNormalizable(var0)) { + + if (var1 == null) { + return false; + } else { + final int var3 = var1.length(); + if (var3 >= 12) { + return false; + } else { + return !Strings.isSpaceLikeUsernameChar(var0) || var3 != 0; + } + } + } else { + return false; + } + } + + public static void tick(final boolean mouseNotYetHandled) { + if (openInstance != null) { + final int var3 = openInstance.getAction(mouseNotYetHandled); + if (var3 != 0) { + if (var3 == 2 && openInstance.label != null && !openInstance.label.equals("")) { + final String var4; + if (openInstance.label.charAt(0) == '[') { + var4 = openInstance.label; + } else { + var4 = Strings.normalize(openInstance.label); + } + + String var5 = null; + if (action == Action.ADD_FRIEND) { + var5 = ContextMenu.addFriend(var4); + } + + if (action == Action.REMOVE_FRIEND) { + var5 = PlayerListEntry.removeFriend(var4); + } + + if (action == Action.ADD_IGNORE) { + var5 = ContextMenu.addIgnore(var4); + } + + if (action == Action.REMOVE_IGNORE) { + var5 = PlayerListEntry.removeIgnore(var4, var4); + } + + if (var5 != null) { + ContextMenu.showChatMessage(ChatMessage.Channel.PRIVATE, var5, 0, var4, null); + } + } + + action = Action.NONE; + openInstance = null; + } + } + } + + public boolean f427() { + if (this._Ab == 0) { + if (JagexApplet.lastTypedKeyCode == KeyState.Code.BACKSPACE && this._Db.length() > 0) { + removeLastCharacterFromStringBuilder(this._Db); + } + + if (this._Db.length() < 12) { + char var2 = Character.toLowerCase(JagexApplet.lastTypedKeyChar); + if (var2 == ' ') { + var2 = '_'; + } + + if (var2 == '_' && this._Db.length() > 0) { + this._Db.append('_'); + } + + if (Strings.isAlpha(var2) || Strings.isDigit(var2)) { + this._Db.append(var2); + } + } + + if (JagexApplet.lastTypedKeyCode == KeyState.Code.ENTER) { + if (this._Db.length() <= 0) { + this._Ab = 1; + } else { + this.label = this._Db.toString(); + this._Ab = 2; + } + } + + if (JagexApplet.lastTypedKeyCode == KeyState.Code.ESCAPE) { + this._Ab = 1; + } + + return true; + } else { + return false; + } + } + + private int getAction(final boolean mouseNotYetHandled) { + this.rootProcessMouseEvents(mouseNotYetHandled); + if (mouseNotYetHandled) { + while (JagexApplet.nextTypedKey()) { + if (JagexApplet.lastTypedKeyCode == KeyState.Code.BACKSPACE && this._Db.length() > 0) { + removeLastCharacterFromStringBuilder(this._Db); + } + + if (a412tmg(JagexApplet.lastTypedKeyChar, this._Db) || this._Db.length() == 0 && JagexApplet.lastTypedKeyChar == '[' || this._Db.length() == 1 && JagexApplet.lastTypedKeyChar == '#' || JagexApplet.lastTypedKeyChar == ']') { + this._Db.append(JagexApplet.lastTypedKeyChar); + } + + if (JagexApplet.lastTypedKeyCode == KeyState.Code.ENTER) { + if (this._Db.length() <= 0) { + return 1; + } + + this.label = this._Db.toString(); + return 2; + } + + if (JagexApplet.lastTypedKeyCode == KeyState.Code.ESCAPE) { + return 1; + } + } + } + + this._zb.label = this._Db.toString(); + if (mouseNotYetHandled && JagexApplet.mouseButtonJustClicked != MouseState.Button.NONE && this.clickButton == MouseState.Button.NONE) { + this._Ab = 1; + } + + return this._Ab; + } + + @SuppressWarnings("WeakerAccess") + public static final class Action { + public static final int NONE = -1; + public static final int ADD_FRIEND = 0; + public static final int REMOVE_FRIEND = 1; + public static final int ADD_IGNORE = 2; + public static final int REMOVE_IGNORE = 3; + } +} diff --git a/src/main/java/funorb/client/lobby/ChatMessage.java b/src/main/java/funorb/client/lobby/ChatMessage.java new file mode 100644 index 0000000..3896504 --- /dev/null +++ b/src/main/java/funorb/client/lobby/ChatMessage.java @@ -0,0 +1,119 @@ +package funorb.client.lobby; + +import funorb.shatteredplans.client.ShatteredPlansClient; +import org.jetbrains.annotations.NotNull; + +public final class ChatMessage { + public final long senderId; + public final boolean _h; + public final int _g; + public final String _o; + public final @NotNull String message; + public final int _c; + public final String senderDisplayName; + public final int _l; + public final int[] _f; + public final String senderName; + public final @NotNull Channel channel; + public final int _e; + public Component component; + + public ChatMessage(final boolean isQuick, + final int c, + final long senderId, + final int l, + final @NotNull Channel channel, + final int e, + final String senderDisplayName, + final int[] f, + final String senderName, + final @NotNull String message, + final boolean h, + final String o, + final int g) { + this._e = e; + this._f = isQuick ? f : null; + this.senderName = senderName; + this.message = message; + this._c = c; + this._h = h; + this._o = o; + this.senderId = senderId; + this._l = l; + this._g = g; + this.channel = channel; + this.senderDisplayName = senderDisplayName; + } + + public ChatMessage(final @NotNull Channel channel, + final String var2, + final int var3, + final String var4, + final @NotNull String message) { + this._h = true; + this.message = message; + this._g = var3; + this._o = var4; + this.senderDisplayName = var2; + this._c = 0; + this.channel = channel; + this.senderId = 0L; + this._e = 0; + this._f = null; + this.senderName = var2; + this._l = 0; + } + + public static String a651(final String var0, String var1, final String var2) { + for (int var3 = var1.indexOf(var0); var3 != -1; var3 = var1.indexOf(var0, var3 + var2.length())) { + var1 = var1.substring(0, var3) + var2 + var1.substring(var3 + var0.length()); + } + + return var1; + } + + public Channel a410() { + if (this._h || (this.channel == Channel.PRIVATE && this._c > 0)) { + return Channel.PRIVATE; + } else if (this.senderId == ShatteredPlansClient.localPlayerId || (PlayerListEntry.serverStatus == PlayerListEntry.ServerStatus.LOADED && ShatteredPlansClient.a988da(this.senderName))) { + return Channel.ROOM; + } else { + return Channel.LOBBY; + } + } + + public enum Channel { + LOBBY, + ROOM, + PRIVATE, + // not sure what these are for! + CHANNEL_4, + CHANNEL_5; + + public int encode() { + return this.ordinal(); + } + + public static Channel decode(final int val) { + return values()[val]; + } + } + + public enum FilterLevel { + ALL, + FRIENDS, + NONE; + + public boolean lessThanOrEqual(final Channel other) { + return this.ordinal() <= other.ordinal(); + } + + public int encode() { + return this.ordinal(); + } + + public static FilterLevel decode(final int val) { + return values()[val]; + } + } +} diff --git a/src/main/java/funorb/client/lobby/Checkbox.java b/src/main/java/funorb/client/lobby/Checkbox.java new file mode 100644 index 0000000..f8fb84a --- /dev/null +++ b/src/main/java/funorb/client/lobby/Checkbox.java @@ -0,0 +1,45 @@ +package funorb.client.lobby; + +import funorb.graphics.Font; +import funorb.graphics.Sprite; + +public final class Checkbox extends Component> { + private final Component _Ab; + private final Component _xb; + + private Checkbox(final Component var3, final Component var4, final String var5) { + super(null); + this._xb = new Component<>(var3); + this._Ab = new Component<>(var4); + this._Ab.label = var5; + this.addChild(this._xb); + this.addChild(this._Ab); + this.recursivelySet_H(); + } + + public Checkbox(final Checkbox var3, final String var4) { + this(var3._xb, var3._Ab, var4); + } + + public Checkbox(final Sprite var3, final Sprite var4, final Component var6) { + this(null, var6, null); + this._xb.sprite = var4; + this._xb.verticalAlignment = Font.VerticalAlignment.MIDDLE; + this._xb._Z = var3; + } + + private void b366() { + this._xb.setBounds(0, 0, this._xb.e474(), this.height); + final int var3 = this._xb.width + 4; + this._Ab.setBounds(var3, 0, -var3 + this.width, this.height); + } + + public int c080() { + return this._xb.e474() + 4 + this._Ab.e474(); + } + + public void a669(final int var1, final int var2, final int var6) { + this.setBounds(var2, var6, var1, Component.LABEL_HEIGHT); + this.b366(); + } +} diff --git a/src/main/java/funorb/client/lobby/ClientLobbyRoom.java b/src/main/java/funorb/client/lobby/ClientLobbyRoom.java new file mode 100644 index 0000000..bccc5dd --- /dev/null +++ b/src/main/java/funorb/client/lobby/ClientLobbyRoom.java @@ -0,0 +1,568 @@ +package funorb.client.lobby; + +import funorb.Strings; +import funorb.awt.MouseState; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.graphics.Sprite; +import funorb.io.Buffer; +import funorb.shatteredplans.C2SPacket; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.JagexApplet; +import funorb.shatteredplans.client.ShatteredPlansClient; +import funorb.util.CollectionUtil; +import funorb.util.PseudoMonotonicClock; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public final class ClientLobbyRoom extends Component> { + private static final int _mlj = 4; + + public static List rooms; + public static Map roomsMap; + + public final int roomId; + public static Sprite[][] GAMEOPT_SPRITES; + public static String currentTooltip; + public static int _qob; + public static Sprite[] ALLOW_SPECTATORS_SPRITES; + public static Sprite[] RATED_GAME_SPRITES; + public static Sprite[] OPEN_TO_ME_SPRITES; + public static Sprite[] WHO_CAN_JOIN_OPTION_SPRITES; + public static String[] WHO_CAN_JOIN_OPTION_TOOLTIPS; + public final byte[] gameSpecificOptions; + private Component askingToJoinLabel; + public boolean notInProgress; + private Component _Wb; + private Component _Ib; + private Component _Db; + private int averageRating; + private Component _Ub; + private boolean youAreAllowedToJoin; + public String[] joinedPlayerNames; + private Component isRatedIcon; + private Component> _Mb; + private long startedAt; + public int status; + private Component[] gameOptionIcons; + private Component _Rb; + public boolean youCanJoin; + public int allowSpectate; + private Component canJoinIcon; + public int finalElapsedTime; + public boolean hasStarted; + private Component _Pb; + public long ownerId; + public int whoCanJoin; + private Component youAreInvitedLabel; + public int maxPlayerCount; + private Component cannotJoinReasonLabel; + private Component playersInGameLabel; + private boolean isRated; + public boolean submittedJoinRequest; + private Component whoCanJoinIcon; + public int statusTimer; + public String ownerName; + public boolean youAreInvited; + public int joinedPlayerCount; + private Component ageLabel; + private Component allowSpectateIcon; + + public ClientLobbyRoom(final int roomId) { + super(null); + this.roomId = roomId; + this.gameSpecificOptions = new byte[ShatteredPlansClient.GAMEOPT_CHOICES_COUNTS.length]; + } + + private static String removalReasonMessage(final int status, final String ownerName) { + if (status == Status.ENTERED_OTHER_GAME) { + return StringConstants.MU_ENTERED_OTHER_GAME; + } else if (status == Status.ROOM_FULL) { + return StringConstants.MU_GAME_IS_FULL; + } else if (status == Status.GAME_HAS_STARTED) { + return StringConstants.MU_GAME_HAS_STARTED; + } else if (status == Status.YOU_DECLINED_INVITE) { + return StringConstants.MU_YOU_DECLINED_INVITE; + } else if (status == Status.INVITE_WITHDRAWN) { + return StringConstants.MU_INVITE_WITHDRAWN; + } else if (status == Status.REQUEST_DECLINED) { + return StringConstants.MU_REQUEST_DECLINED; + } else if (status == Status.REQUEST_WITHDRAWN) { + return StringConstants.MU_REQUEST_WITHDRAWN; + } else if (status == Status.ALL_PLAYERS_HAVE_LEFT) { + return Strings.format(StringConstants.MU_ALL_PLAYERS_HAVE_LEFT, ownerName); + } else { + return null; + } + } + + public static void tick(final boolean var0, final int var4) { + final boolean var6 = Component.GAME_LIST_SCROLL_PANE.processScrollInput(var0, ShatteredPlansClient.currentContextMenuParent == Component.GAME_LIST_SCROLL_PANE, (2 + Component.LABEL_HEIGHT) * 2, (Component.LABEL_HEIGHT * 4 + 8) * var4); + final List rooms = Component.GAME_LIST_SCROLL_PANE.content.children; + final long now = PseudoMonotonicClock.currentTimeMillis(); + + for (final ClientLobbyRoom room : rooms) { + boolean var12 = false; + if (room.children == null) { + room._Ub = new Component<>(Component.UNSELECTED_LABEL_DARK_1); + room.addChild(room._Ub); + room._Ub.textAlignment = Font.HorizontalAlignment.CENTER; + room._Pb = new Component<>(Component.UNSELECTED_LABEL_DARK_2); + room.addChild(room._Pb); + room._Rb = new Component<>(Component.UNSELECTED_LABEL_DARK_1); + room.addChild(room._Rb); + room._Rb._kb = 0; + room._Wb = new Component<>(Component.UNSELECTED_LABEL_DARK_1); + room.addChild(room._Wb); + room._Wb._kb = 0; + room._Ib = new Component<>(Component.UNSELECTED_LABEL_DARK_2); + room.addChild(room._Ib); + room._Ib.textAlignment = Font.HorizontalAlignment.RIGHT; + room._Mb = new Component<>(Component.UNSELECTED_LABEL_DARK_1); + room.addChild(room._Mb); + room.gameOptionIcons = new Component[ShatteredPlansClient.GAMEOPT_CHOICES_COUNTS.length]; + room.whoCanJoinIcon = new Component<>(null); + room._Mb.addChild(room.whoCanJoinIcon); + + room.canJoinIcon = new Component<>(null); + room._Mb.addChild(room.canJoinIcon); + + room.allowSpectateIcon = new Component<>(null); + room._Mb.addChild(room.allowSpectateIcon); + + room.isRatedIcon = new Component<>(null); + room._Mb.addChild(room.isRatedIcon); + + final Component var14 = room.whoCanJoinIcon; + final Component var15 = room.isRatedIcon; + room.allowSpectateIcon.verticalAlignment = Font.VerticalAlignment.MIDDLE; + final Component var16 = room.canJoinIcon; + var16.verticalAlignment = Font.VerticalAlignment.MIDDLE; + var15.verticalAlignment = Font.VerticalAlignment.MIDDLE; + var14.verticalAlignment = Font.VerticalAlignment.MIDDLE; + + for (int i = 0; i < ShatteredPlansClient.GAMEOPT_CHOICES_COUNTS.length; ++i) { + room.gameOptionIcons[i] = new Component<>(null); + if (((1 << (_mlj + i)) & Drawing.WHITE) != 0) { + room._Mb.addChild(room.gameOptionIcons[i]); + } + room.gameOptionIcons[i].verticalAlignment = Font.VerticalAlignment.MIDDLE; + } + + room.ageLabel = new Component<>(Component.UNSELECTED_LABEL_DARK_2); + room.addChild(room.ageLabel); + room.ageLabel.textAlignment = Font.HorizontalAlignment.RIGHT; + room.playersInGameLabel = new Component<>(Component.UNSELECTED_LABEL_DARK_2); + room.addChild(room.playersInGameLabel); + room.youAreInvitedLabel = new Component<>(Component.UNSELECTED_LABEL); + room.addChild(room.youAreInvitedLabel); + room.askingToJoinLabel = new Component<>(Component.UNSELECTED_LABEL); + room.addChild(room.askingToJoinLabel); + room.cannotJoinReasonLabel = new Component<>(Component.LABEL); + room.addChild(room.cannotJoinReasonLabel); + room.recursivelySet_H(); + room._Db = new Component<>(Component.GREEN_BUTTON); + var12 = true; + room.addChild(room._Db); + } + + room._Ub.label = null; + room._Ub.height = 0; + final Component var14 = room._Ub; + var14.width = 0; + room._Db.label = null; + room._Db.height = 0; + final Component var15 = room._Db; + var15.width = 0; + room._Pb.label = null; + final Component var16 = room._Pb; + room._Pb.height = 0; + room._Rb.label = null; + var16.width = 0; + room._Rb.height = 0; + final Component var40 = room._Rb; + var40.width = 0; + room._Wb.label = null; + room._Wb.height = 0; + final Component var18 = room._Wb; + var18.width = 0; + room._Ib.label = null; + final Component var19 = room._Ib; + room._Ib.height = 0; + var19.width = 0; + room._Mb.label = null; + final Component var20 = room._Mb; + room._Mb.height = 0; + var20.width = 0; + + for (int i = 0; i < ShatteredPlansClient.GAMEOPT_CHOICES_COUNTS.length; ++i) { + room.gameOptionIcons[i].sprite = null; + room.gameOptionIcons[i].height = 0; + room.gameOptionIcons[i].width = 0; + } + + room.whoCanJoinIcon.sprite = null; + room.whoCanJoinIcon.height = 0; + final Component var41 = room.whoCanJoinIcon; + room.isRatedIcon.sprite = null; + var41.width = 0; + room.isRatedIcon.height = 0; + final Component var22 = room.isRatedIcon; + room.canJoinIcon.sprite = null; + var22.width = 0; + final Component var23 = room.canJoinIcon; + room.canJoinIcon.height = 0; + room.allowSpectateIcon.sprite = null; + var23.width = 0; + final Component var24 = room.allowSpectateIcon; + room.allowSpectateIcon.height = 0; + var24.width = 0; + room.ageLabel.label = null; + final Component var25 = room.ageLabel; + room.ageLabel.height = 0; + room.playersInGameLabel.label = null; + var25.width = 0; + room.playersInGameLabel.height = 0; + final Component var26 = room.playersInGameLabel; + room.youAreInvitedLabel.label = null; + var26.width = 0; + room.youAreInvitedLabel.height = 0; + final Component var27 = room.youAreInvitedLabel; + room.askingToJoinLabel.label = null; + var27.width = 0; + room.askingToJoinLabel.height = 0; + final Component var28 = room.askingToJoinLabel; + var28.width = 0; + room.cannotJoinReasonLabel.label = null; + room.cannotJoinReasonLabel.height = 0; + final Component var29 = room.cannotJoinReasonLabel; + var29.width = 0; + room.width = Component.GAME_LIST_SCROLL_PANE.content.width; + + int var30 = 0; + if (room.isInMap()) { + if (room.hasStarted) { + if (room.finalElapsedTime >= 0) { + room._Ub.label = StringConstants.STATUS_CONCLUDED; + } else if (room.notInProgress && (room.youCanJoin || room.youAreInvited)) { + room._Db.label = StringConstants.STATUS_JOIN; + } else if (room.allowSpectate == 2) { + room._Db.label = StringConstants.STATUS_SPECTATE; + } else { + room._Ub.label = StringConstants.STATUS_PLAYING; + } + } else if (room.youCanJoin || room.youAreInvited) { + room._Db.label = StringConstants.STATUS_JOIN; + } else if (room.youAreAllowedToJoin) { + room._Ub.label = StringConstants.STATUS_FULL; + } else { + room._Ub.label = StringConstants.STATUS_PRIVATE; + } + + if (room._Db.label == null) { + room._Ub.setBounds(0, var30, 68, Component.LABEL_HEIGHT); + } else { + room._Db.setBounds(0, var30, 68, Component.LABEL_HEIGHT); + } + + room._Pb.label = room._Pb.font.truncateWithEllipsisToFit(room.ownerName, 78); + room._Pb.setBounds(70, var30, 78, Component.LABEL_HEIGHT); + if (room._Pb.isMouseOverTarget && !room._Pb.label.equals(room.ownerName)) { + currentTooltip = room.ownerName; + } + + room._Rb.label = Integer.toString(room.joinedPlayerCount); + int var32; + if (room.notInProgress) { + room._Wb.label = "/" + room.maxPlayerCount; + room._Rb.textAlignment = Font.HorizontalAlignment.RIGHT; + var32 = (348 - room._Wb.font.measureLineWidth("/")) / 2; + room._Rb.setBounds(150, var30, var32 - 150, Component.LABEL_HEIGHT); + room._Wb.setBounds(var32, var30, -var32 + 198, Component.LABEL_HEIGHT); + } else { + room._Rb.textAlignment = Font.HorizontalAlignment.CENTER; + room._Rb.setBounds(150, var30, 48, Component.LABEL_HEIGHT); + } + + room._Ib.label = Integer.toString(room.averageRating); + room._Ib.setBounds(200, var30, 48, Component.LABEL_HEIGHT); + var32 = 250; + room._Mb.setBounds(var32, var30, 365 - var32 - 2, Component.LABEL_HEIGHT); + int var33 = _qob; + Sprite var34; + var34 = WHO_CAN_JOIN_OPTION_SPRITES[room.whoCanJoin]; + room.whoCanJoinIcon.sprite = var34; + room.whoCanJoinIcon.setBounds(var33, 0, var34.offsetX, room._Mb.height); + var33 += var34.offsetX + _qob; + + final boolean var35 = room.youCanJoin || room.youAreInvited; + var34 = OPEN_TO_ME_SPRITES[var35 ? 1 : 0]; + room.canJoinIcon.sprite = var34; + room.canJoinIcon.setBounds(var33, 0, var34.offsetX, room._Mb.height); + var33 += _qob + var34.offsetX; + + var34 = ALLOW_SPECTATORS_SPRITES[room.allowSpectate - 1]; + room.allowSpectateIcon.sprite = var34; + room.allowSpectateIcon.setBounds(var33, 0, var34.offsetX, room._Mb.height); + var33 += _qob + var34.offsetX; + + var34 = RATED_GAME_SPRITES[!room.isRated ? 0 : 1]; + room.isRatedIcon.sprite = var34; + room.isRatedIcon.setBounds(var33, 0, var34.offsetX, room._Mb.height); + var33 += _qob + var34.offsetX; + + if (GAMEOPT_SPRITES != null) { + for (int i = 0; i < ShatteredPlansClient.GAMEOPT_CHOICES_COUNTS.length; ++i) { + if (GAMEOPT_SPRITES[i] != null && (((1 << (i + _mlj)) & Drawing.WHITE) != 0)) { + var34 = GAMEOPT_SPRITES[i][room.gameSpecificOptions[i] & 255]; + room.gameOptionIcons[i].sprite = var34; + room.gameOptionIcons[i].setBounds(var33, 0, var34.offsetX, room._Mb.height); + var33 += _qob + var34.offsetX; + } + } + } + + final int var43 = (room._Mb.width - var33) / 2; + if (var43 > 0) { + room.whoCanJoinIcon.x += var43; + final Component oc = room.canJoinIcon; + oc.x += var43; + final Component ac = room.allowSpectateIcon; + ac.x += var43; + Component kb = room.isRatedIcon; + kb.x += var43; + + for (int var36 = 0; ShatteredPlansClient.GAMEOPT_CHOICES_COUNTS.length > var36; ++var36) { + kb = room.gameOptionIcons[var36]; + kb.x += var43; + } + } + + if (room.hasStarted) { + int millis = room.finalElapsedTime; + if (millis < 0) { + millis = (int) (now - room.startedAt); + } + + int seconds = millis / 1000; + int minutes = seconds / 60; + seconds %= 60; + if (minutes >= 60) { + final int hours = minutes / 60; + minutes %= 60; + room.ageLabel.label = hours + ":" + minutes / 10 + minutes % 10 + ":" + seconds / 10 + seconds % 10; + } else { + room.ageLabel.label = minutes + ":" + seconds / 10 + seconds % 10; + } + } + + room.ageLabel.setBounds(365, var30, room.width - 365, Component.LABEL_HEIGHT); + var30 += Component.LABEL_HEIGHT; + if (room.joinedPlayerNames != null) { + var30 += 2; + + final String playersInGame = Arrays.stream(room.joinedPlayerNames, 0, room.joinedPlayerCount) + .collect(Collectors.joining(", ", StringConstants.PLAYERS_IN_GAME, "")); + room.playersInGameLabel.label = playersInGame; + final int lineCount = room.playersInGameLabel.font.breakLines(playersInGame, room.width - 2 * room.playersInGameLabel._kb); + room.playersInGameLabel.setBounds(0, var30, room.width, Component.LABEL_HEIGHT * lineCount); + var30 += lineCount * Component.LABEL_HEIGHT; + } + + if (room.youAreInvited) { + room.youAreInvitedLabel.label = Strings.format(StringConstants.YOU_ARE_INVITED_TO_XS_GAME, room.ownerName); + room.youAreInvitedLabel.setBounds(ShatteredPlansClient._tga, var30, room.width - ShatteredPlansClient._tga * 2, Component.LABEL_HEIGHT); + var30 += Component.LABEL_HEIGHT; + } + + if (room.submittedJoinRequest) { + room.askingToJoinLabel.label = Strings.format(StringConstants.ASKING_TO_JOIN_XS_GAME, room.ownerName); + room.askingToJoinLabel.setBounds(ShatteredPlansClient._tga, var30, -(2 * ShatteredPlansClient._tga) + room.width, Component.LABEL_HEIGHT); + var30 += Component.LABEL_HEIGHT; + } + } + + final String message = removalReasonMessage(room.status, room.ownerName); + if (message != null) { + final int var33 = room.cannotJoinReasonLabel.font.breakLines(message, -ShatteredPlansClient._tga - ShatteredPlansClient._tga + room.width); + room.cannotJoinReasonLabel.label = message; + room.cannotJoinReasonLabel._I = 256 * room.statusTimer / ShatteredPlansClient.STATUS_MESSAGE_TIMEOUT_DURATION; + room.cannotJoinReasonLabel.setBounds(ShatteredPlansClient._tga, var30, room.width - ShatteredPlansClient._tga * 2, Component.LABEL_HEIGHT * var33); + var30 += var33 * Component.LABEL_HEIGHT; + } + + if (!var6) { + room._gb = var30 - room.height; + } + + if (var12) { + Component.GAME_LIST_SCROLL_PANE.content.placeAfter(null, room); + } + + for (int i = 0; i < ShatteredPlansClient.GAMEOPT_CHOICES_COUNTS.length; ++i) { + if (room.gameOptionIcons[i].isMouseOverTarget) { + final String tooltip = ShatteredPlansClient.GAMEOPT_TOOLTIPS == null ? null + : ShatteredPlansClient.GAMEOPT_TOOLTIPS[i] == null ? null + : ShatteredPlansClient.GAMEOPT_TOOLTIPS[i][room.gameSpecificOptions[i] & 255]; + if (tooltip == null) { + currentTooltip = StringConstants.GAMEOPT_LABELS[i]; + } else { + currentTooltip = StringConstants.GAMEOPT_LABELS[i] + " - " + tooltip; + } + } + } + + if (room.whoCanJoinIcon.isMouseOverTarget) { + final String tooltip; + if (room.whoCanJoin == 1) { + tooltip = StringConstants.RUNESCAPE_CLAN; + } else { + tooltip = WHO_CAN_JOIN_OPTION_TOOLTIPS[room.whoCanJoin]; + } + + currentTooltip = StringConstants.WHO_CAN_JOIN + " - " + tooltip; + } + + if (room.isRatedIcon.isMouseOverTarget) { + currentTooltip = room.isRated ? StringConstants.RATED_GAME : StringConstants.UNRATED_GAME; + } + + if (room.canJoinIcon.isMouseOverTarget) { + currentTooltip = room.youCanJoin || room.youAreInvited ? StringConstants.YOU_CAN_JOIN + : room.notInProgress ? StringConstants.YOU_CAN_ASK_TO_JOIN + : StringConstants.YOU_CANNOT_JOIN_IN_PROGRESS; + } + + if (room.allowSpectateIcon.isMouseOverTarget) { + currentTooltip = room.allowSpectate != 2 ? StringConstants.YOU_CAN_NOT_SPECTATE : StringConstants.YOU_CAN_SPECTATE; + } + + if (room.clickButton != MouseState.Button.NONE && room.isInMap()) { + if (room._Db.clickButton == MouseState.Button.NONE) { + a458aj(room, room.ownerName); + } else if (!room.hasStarted || (room.notInProgress && (room.youCanJoin || room.youAreInvited))) { + C2SPacket.requestToJoinRoom(room.roomId); + } else { + C2SPacket.spectateGame(room.roomId); + } + } + } + } + + private static void a458aj(final ClientLobbyRoom var1, final String var2) { + ShatteredPlansClient.showContextMenu(Component.GAME_LIST_SCROLL_PANE, var1, 0L, null, null, var1.roomId, null); + if (var1.hasStarted && (var1.allowSpectate == 2 || JagexApplet.adminLevel >= 2)) { + ContextMenu.openInstance.view.addItem(Strings.format(StringConstants.SPECTATE_XS_GAME, var2), ContextMenu.ClickAction.SPECTATE_GAME); + } + + ContextMenu.openInstance.a487(); + if (ContextMenu.openInstance.roomId == ContextMenu.roomShowingPlayers) { + ContextMenu.openInstance.view.addItem(Strings.format(StringConstants.HIDE_PLAYERS_IN_XS_GAME, var2), ContextMenu.ClickAction.HIDE_PLAYERS_IN_GAME); + } else { + ContextMenu.openInstance.view.addItem(Strings.format(StringConstants.SHOW_PLAYERS_IN_XS_GAME, var2), ContextMenu.ClickAction.SHOW_PLAYERS_IN_GAME); + } + + ContextMenu.openInstance.view.positionRelativeToTarget(JagexApplet.mousePressX, JagexApplet.mousePressY); + } + + public static ClientLobbyRoom lookup(final int roomId) { + return roomsMap == null ? null : roomsMap.get(roomId); + } + + public static void add(final ClientLobbyRoom room) { + rooms.remove(room); + CollectionUtil.insertSorted(rooms, room, ClientLobbyRoom::lessThan); + } + + public boolean isInMap() { + return roomsMap.containsKey(this.roomId); + } + + public void initializeFromServer(@SuppressWarnings("SameParameterValue") final Buffer packet, final boolean includesJoinedPlayerCount) { + if (includesJoinedPlayerCount) { + this.joinedPlayerCount = packet.readUByte(); + } + this.maxPlayerCount = packet.readUByte(); + this.whoCanJoin = packet.readUByte(); + final int var4 = packet.readUByte(); + final boolean includesJoinedPlayerNames = (var4 & 2) != 0; + final boolean concluded = (var4 & 4) != 0; + this.notInProgress = (var4 & 8) != 0; + this.allowSpectate = (var4 & 16) == 0 ? 1 : 2; + this.isRated = (var4 & 32) != 0; + this.hasStarted = (var4 & 64) != 0; + this.youAreAllowedToJoin = (var4 & 128) != 0; + this.youCanJoin = this.youAreAllowedToJoin && this.joinedPlayerCount < this.maxPlayerCount; + packet.readBytes(this.gameSpecificOptions, this.gameSpecificOptions.length); + this.averageRating = packet.readUShort(); + this.startedAt = PseudoMonotonicClock.currentTimeMillis() - (long) packet.readInt(); + if (concluded) { + this.finalElapsedTime = packet.readInt(); + } else { + this.finalElapsedTime = -1; + } + + this.ownerId = packet.readLong(); + final int var7 = packet.pos; + this.ownerName = packet.readNullTerminatedString(); + if (includesJoinedPlayerNames) { + packet.pos = var7; + this.joinedPlayerNames = new String[this.joinedPlayerCount]; + for (int i = 0; i < this.joinedPlayerCount; ++i) { + this.joinedPlayerNames[i] = packet.readNullTerminatedString(); + } + } else { + this.joinedPlayerNames = null; + } + } + + private boolean lessThan(final ClientLobbyRoom var1) { + final boolean var3 = this.youAreInvited || this.status == Status.ROOM_FULL; + final boolean var4 = var1.youAreInvited || var1.status == Status.ROOM_FULL; + if (var3 == var4) { + if (!var3) { + if (this.youCanJoin != var1.youCanJoin) { + return this.youCanJoin; + } + + if (this.youCanJoin && this.whoCanJoin != var1.whoCanJoin) { + return this.whoCanJoin < var1.whoCanJoin; + } + } + + if (this.hasStarted == var1.hasStarted) { + if (this.hasStarted) { + final boolean var5 = this.notInProgress || this.allowSpectate == 2; + final boolean var6 = var1.notInProgress || var1.allowSpectate == 2; + if (var5 == var6) { + return this.startedAt > var1.startedAt; + } else { + return var5; + } + } else { + return this.startedAt < var1.startedAt; + } + } else { + return !this.hasStarted; + } + } else { + return var3; + } + } + + @SuppressWarnings("WeakerAccess") + public static final class Status { + public static final int NONE = 0; + public static final int ENTERED_OTHER_GAME = 3; + public static final int ROOM_FULL = 6; + public static final int GAME_HAS_STARTED = 7; + public static final int YOU_DECLINED_INVITE = 8; + public static final int INVITE_WITHDRAWN = 9; + public static final int REQUEST_DECLINED = 10; + public static final int REQUEST_WITHDRAWN = 11; + public static final int ALL_PLAYERS_HAVE_LEFT = 14; + } +} diff --git a/src/main/java/funorb/client/lobby/Component.java b/src/main/java/funorb/client/lobby/Component.java new file mode 100644 index 0000000..9835462 --- /dev/null +++ b/src/main/java/funorb/client/lobby/Component.java @@ -0,0 +1,1530 @@ +package funorb.client.lobby; + +import funorb.awt.MouseState; +import funorb.cache.ResourceLoader; +import funorb.commonui.form.DobToEnableChatForm; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.graphics.NineSliceSprite; +import funorb.graphics.PalettedSymbol; +import funorb.graphics.Sprite; +import funorb.graphics.SpriteFont; +import funorb.graphics.SpriteResource; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.JagexApplet; +import funorb.shatteredplans.client.ShatteredPlansClient; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +public class Component> { + public static final int[] CHANNEL_TEXT_COLORS_2 = new int[5]; + public static final int LABEL_HEIGHT = 15; + public static final String[] CHAT_FILTER_LABELS = new String[3]; + public static final int[] CHANNEL_TEXT_COLORS_1 = new int[5]; + private static final int UNSELECTED_TEXT_COLOR = 0xffcc66; + public static Component LABEL_DARK_1; + public static Component _cna; + public static Component CLOSE_BUTTON; + public static Component LABEL_DARK_2; + public static int _si; + public static Component NAME_LABEL; + public static vm_ _ofb; + public static Component[] chatFilterIcons; + public static Component>[] chatFilterButtons; + public static Sprite DISPLAY_NAME_CHANGED; + public static Component> lobbyBrowserLeftPanel; + public static Component INVITE_PLAYER_LIST_HEADING_RATING; + public static Component RETURN_TO_MAIN_MENU_BUTTON; + private static QuickChatCategories _guiA; + private static Component ALL_GAMES_HEADING; + private static Component COLUMN_HEADING_MEDIUM_CENTER; + private static Component COLUMN_HEADING_MEDIUM_RIGHT; + private static Component GAME_LIST_HEADING_OWNER; + private static Component GAME_LIST_HEADING_AVG_RATING; + public static Component YOU_HAVE_BEEN_KICKED_OK_BUTTON; + public static Component _mpa; + public static ScrollPane JOINED_PLAYERS_TABLE; + public static int lastLayoutHeight; + public static int lastLayoutWidth; + private static Component> lobbyBrowserPlayerList; + public static Component UNSELECTED_LABEL_DARK_2; + private static int chatFilterButtonCount; + public static Component> YOU_HAVE_BEEN_KICKED_DIALOG; + public static Component> JOINED_PLAYERS_PANEL; + public static PopupMenu _hdt; + public static Component PLAY_RATED_GAME_BUTTON; + public static Component CREATE_UNRATED_GAME_BUTTON; + public static ActionButton[][] GAME_OPTIONS_BUTTONS; + public static Component GAME_OPTIONS_HEADING; + public static Component JOINED_PLAYER_COUNT_LABEL; + public static Component> INVITE_PLAYER_LIST_PANEL; + public static Component INVITE_PLAYERS_BUTTON; + public static Component GREEN_BUTTON; + public static Component FIND_OPPONENTS_BUTTON; + public static PlayerList FRIEND_LIST; + public static Component _tmt; + public static Component> _tgc; + public static int _rcl; + public static int CROWNS_COUNT; + public static Component> _taio; + public static Component RETURN_TO_LOBBY_BUTTON; + public static ScrollPane> _jiI; + private static Component _rsEb; + public static Component> WAITING_TO_START_LABEL; + public static Component NAME_LABEL_2; + private static Component GAME_LIST_HEADING_STATUS; + public static Component> FRIEND_LIST_PANEL; + public static Component _cgC; + private static Component BACK_BUTTON; + public static SpriteFont CHAT_FONT; + public static ScrollBar SCROLL_BAR; + public static Component> LOBBY_RIGHT_PANEL; + private static PlayerList PLAYER_LIST; + public static Checkbox CHECKBOX; + private static Component MEDIUM_BUTTON; + public static Component TAB_ACTIVE; + public static Component INVITE_PLAYERS_LABEL; + public static Component _hlI; + public static Component CLOSE_BUTTON_2; + public static Component BIG_BUTTON; + private static Component GAME_LIST_HEADING_OPTIONS; + private static Component GAMEOPT_BUTTON; + public static Component UNSELECTED_LABEL; + private static Component GAME_LIST_HEADING_ELAPSED_TIME; + public static Component GAME_OWNER_HEADING; + public static Component UNSELECTED_LABEL_DARK_1; + public static Component _uaf; + public static Component LABEL; + public static ScrollPane GAME_LIST_SCROLL_PANE; + public static ScrollPane INVITE_PLAYER_LIST_SCROLL_PANE; + public static TabbedPlayerListWrapper lobbyBrowserTabbedPlayerList; + private static Component GAME_LIST_HEADING_PLAYERS; + private static Component CHAT_FILTER_BUTTON; + public static Component[] GAME_OPTIONS_LABELS; + public static Component TAB_INACTIVE; + private static boolean mouseOverConsumed; + private static boolean clickConsumed; + private static SpriteFont GENERAL_FONT; + private static Component CHAT_BUTTON; + public static Component RED_BUTTON; + private static Component HEADING; + public static Component POPUP; + private static Component COLUMN_HEADING_MEDIUM_LEFT; + public static Component RATED_GAME_TIPS_LABEL; + public static Component> GAME_INFO_CONTAINER; + private static Component> GAME_LIST_PANEL; + public static Component YOU_HAVE_BEEN_KICKED_LABEL; + public static Component INVITE_PLAYER_LIST_HEADING_NAME; + public static Sprite[] CHAT_FILTER_SPRITES; + public static Component _a; + private static Component> _adc; + public static Component[] chatFilterLabels; + private static Component[] chatFilterChannelLabels; + public static Component RATING_LABEL; + public static Component YOUR_RATING_LABEL; + public static Component> GAME_OPTIONS_CONTAINER; + public static Component SERVER_INFO_LABEL; + public static Component LOCATION_LABEL; + private static Component COLUMN_HEADING_LARGE; + public static Component _nld; + public static PlayerList IGNORE_LIST; + + public int _I = 256; + public boolean enabled = true; + public int y2; + protected Sprite _Z; + public int textColor; + private int _V = Integer.MIN_VALUE; + private Sprite disabledSprite; + public int _w; + public int _kb; + private int _t = Integer.MIN_VALUE; + public int x = 0; + public @NotNull Font.HorizontalAlignment textAlignment = Font.HorizontalAlignment.LEFT; + public Sprite sprite; + @MagicConstant(valuesFromClass = MouseState.Button.class) + protected int dragButton; + public int _Y; + protected boolean _r; + protected @NotNull Font.VerticalAlignment verticalAlignment = Font.VerticalAlignment.TOP; + private Sprite mouseHeldSprite; + public Font font; + private int _T = Integer.MIN_VALUE; + public Sprite[] mouseOverNineSliceSprites; + private Sprite mouseOverSprite; + public List children; + private Sprite[] mouseHeldNineSliceSprites; + private int _J = Integer.MIN_VALUE; + private int _W = -1; + public String _u; + public int mouseOverTextColor = -1; + public int _gb; + @MagicConstant(valuesFromClass = MouseState.Button.class) + public int clickButton; + private Sprite[] disabledNineSliceSprites; + public int _qb = -1; + public int width; + public Sprite[] nineSliceSprites; + protected boolean isDraggable; + private Sprite[] activeNineSliceSprites; + public int x2; + public int relativeClickX; + public boolean selected; + public boolean isMouseOver; + public String label; + public int y = 0; + public int height; + public int _ab = -1; + public boolean isMouseOverTarget; + private int relativeClickY; + private int _tb; + private boolean _H; + private int _cb; + private int _S; + + public Component(final Component attrsSrc) { + this(attrsSrc, 0, 0, null); + } + + public Component(final Component attrsSrc, final String label) { + this(attrsSrc, 0, 0, label); + } + + protected Component() { + this(null, 0, 0, null); + } + + protected Component(final Component attrsSrc, final int var6, final int var7, final String label) { + this.width = var6; + this.height = var7; + this.copyAttributesFrom(attrsSrc); + this.label = label; + } + + public static String a369(final String var0) { + final int var3 = var0.length(); + final int var4 = "
".length(); + final int var5 = "
".length(); + int var6 = var3; + final int var7 = -var4 + var5; + int var8 = 0; + + while (true) { + var8 = var0.indexOf("
", var8); + if (var8 < 0) { + break; + } + + var6 += var7; + var8 += var4; + } + + final StringBuilder var11 = new StringBuilder(var6); + int var9 = 0; + + while (true) { + final int var10 = var0.indexOf("
", var9); + if (var10 < 0) { + var11.append(var0.substring(var9)); + return var11.toString(); + } + + var11.append(var0, var9, var10); + var11.append("
"); + var9 = var10 + var4; + } + } + + public static void a469(final ResourceLoader spriteLoader, final ResourceLoader fontLoader, final @NotNull Sprite[][] gameoptSprites) { + a674m(spriteLoader, fontLoader); + a460bq(spriteLoader); + a958tb(spriteLoader, gameoptSprites); + initializeChatResources(spriteLoader); + initializeRuleStrings(); + initializeLobbyBrowserComponents(); + a487te(); + } + + private static void a674m(final ResourceLoader spriteLoader, final ResourceLoader fontLoader) { + final PalettedSymbol[] crowns = SpriteResource.loadPalettedSprites(spriteLoader, "lobby", "crowns"); + CROWNS_COUNT = crowns.length; + final int[] crowsAscents = new int[crowns.length]; + for (int i = 0; i < CROWNS_COUNT; ++i) { + crowsAscents[i] = 10; + } + + _rcl = 2; + _si = 11; + ShatteredPlansClient._tga = 4; + ClientLobbyRoom._qob = 2; + final SpriteFont LARGE_FONT = SpriteResource.loadSpriteFont(spriteLoader, fontLoader, "largefont"); + GENERAL_FONT = SpriteResource.loadSpriteFont(spriteLoader, fontLoader, "generalfont"); + CHAT_FONT = SpriteResource.loadSpriteFont(spriteLoader, fontLoader, "chatfont"); + LARGE_FONT.setSymbols(crowns, crowsAscents); + GENERAL_FONT.setSymbols(crowns, crowsAscents); + CHAT_FONT.setSymbols(crowns, crowsAscents); + final Component var7 = new Component<>(null); + var7.font = LARGE_FONT; + var7.textColor = Drawing.WHITE; + var7._Y = LABEL_HEIGHT; + var7.verticalAlignment = Font.VerticalAlignment.MIDDLE; + var7.textAlignment = Font.HorizontalAlignment.CENTER; + final Component var9 = new Component<>(null); + var9.textColor = Drawing.WHITE; + var9._Y = LABEL_HEIGHT; + var9.font = GENERAL_FONT; + var9.verticalAlignment = Font.VerticalAlignment.MIDDLE; + var9.textAlignment = Font.HorizontalAlignment.CENTER; + HEADING = new Component<>(var7); + HEADING.nineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "heading")); + _cna = new Component<>(null); + _cna.nineSliceSprites = createColumnHeadingSprites(120, 0x404040, 0x808080, false, false); + _mpa = new Component<>(null); + _mpa.nineSliceSprites = createGradientOutlineSprites(114, 0x606060, 0x606060, 1); + POPUP = new Component<>(null); + POPUP.nineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "popup")); + final Sprite[] POPUP_MOUSE_OVER_SPRITES = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "popup_mouseover")); + final Sprite[] TAB_ACTIVE_SPRITES = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "tab_active")); + TAB_ACTIVE = new Component<>(var7); + TAB_ACTIVE.nineSliceSprites = TAB_ACTIVE_SPRITES; + CLOSE_BUTTON = new Component<>(null); + CLOSE_BUTTON.sprite = SpriteResource.loadSprite(spriteLoader, "lobby", "closebutton"); + CLOSE_BUTTON.mouseOverSprite = SpriteResource.loadSprite(spriteLoader, "lobby", "closebutton_mouseover"); + COLUMN_HEADING_LARGE = new Component<>(var7); + COLUMN_HEADING_LARGE.nineSliceSprites = createColumnHeadingSprites(40, 0x1f1f1f, 0x3a3a3a, true, true); + COLUMN_HEADING_MEDIUM_LEFT = new Component<>(var9); + COLUMN_HEADING_MEDIUM_LEFT._kb = 2; + COLUMN_HEADING_MEDIUM_LEFT.nineSliceSprites = createColumnHeadingSprites(30, 0x1f1f1f, 0x3a3a3a, true, false); + COLUMN_HEADING_MEDIUM_CENTER = new Component<>(var9); + COLUMN_HEADING_MEDIUM_CENTER._kb = 2; + COLUMN_HEADING_MEDIUM_CENTER.nineSliceSprites = createColumnHeadingSprites(30, 0x1f1f1f, 0x3a3a3a, false, false); + COLUMN_HEADING_MEDIUM_RIGHT = new Component<>(var9); + COLUMN_HEADING_MEDIUM_RIGHT._kb = 2; + COLUMN_HEADING_MEDIUM_RIGHT.nineSliceSprites = createColumnHeadingSprites(30, 0x1f1f1f, 0x3a3a3a, false, true); + LABEL = new Component<>(null); + LABEL.textColor = 0xcccccc; + LABEL._Y = LABEL_HEIGHT; + LABEL.verticalAlignment = Font.VerticalAlignment.MIDDLE; + LABEL.font = GENERAL_FONT; + UNSELECTED_LABEL = new Component<>(LABEL); + UNSELECTED_LABEL._ab = Drawing.WHITE; + UNSELECTED_LABEL._W = 0x808080; + UNSELECTED_LABEL.mouseOverTextColor = Drawing.WHITE; + UNSELECTED_LABEL.textColor = UNSELECTED_TEXT_COLOR; + UNSELECTED_LABEL._qb = Drawing.WHITE; + final Component LARGE_LABEL = new Component<>(UNSELECTED_LABEL); + LARGE_LABEL.textColor = Drawing.WHITE; + LARGE_LABEL._Y = LABEL_HEIGHT; + LARGE_LABEL.font = LARGE_FONT; + LABEL_DARK_1 = new Component<>(LABEL); + LABEL_DARK_1.nineSliceSprites = createColumnHeadingSprites(16, 0x222222, 0x222222, false, false); + LABEL_DARK_1._kb = 2; + LABEL_DARK_2 = new Component<>(LABEL); + LABEL_DARK_2.nineSliceSprites = createColumnHeadingSprites(16, 0x171717, 0x171717, false, false); + LABEL_DARK_2._kb = 2; + UNSELECTED_LABEL_DARK_1 = new Component<>(LABEL_DARK_1); + UNSELECTED_LABEL_DARK_1.copyAttributesFrom(UNSELECTED_LABEL); + UNSELECTED_LABEL_DARK_2 = new Component<>(LABEL_DARK_2); + UNSELECTED_LABEL_DARK_2.copyAttributesFrom(UNSELECTED_LABEL); + _hdt = new PopupMenu(POPUP, POPUP_MOUSE_OVER_SPRITES, LABEL, UNSELECTED_LABEL, 3, 2, ClientLobbyRoom._qob, 3, LABEL_HEIGHT); + TAB_INACTIVE = new Component<>(UNSELECTED_LABEL); + TAB_INACTIVE.textAlignment = Font.HorizontalAlignment.CENTER; + TAB_INACTIVE.nineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "tab_inactive")); + TAB_INACTIVE.mouseOverNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "tab_mouseover")); + TAB_INACTIVE.activeNineSliceSprites = TAB_ACTIVE_SPRITES; + _tmt = new Component<>(null); + _tmt.nineSliceSprites = createGradientOutlineSprites(206, 1856141, 1127256, -1); + _rsEb = new Component<>(null); + _rsEb.nineSliceSprites = createGradientOutlineSprites(290, 11579568, 6052956, -1); + BIG_BUTTON = new Component<>(LARGE_LABEL); + BIG_BUTTON._T = 1; + BIG_BUTTON.textAlignment = Font.HorizontalAlignment.CENTER; + BIG_BUTTON._J = 1; + BIG_BUTTON._t = 1; + BIG_BUTTON._V = 1; + MEDIUM_BUTTON = new Component<>(BIG_BUTTON); + final Component smallButton = new Component<>(UNSELECTED_LABEL); + smallButton._V = 1; + smallButton._t = 1; + smallButton.textAlignment = Font.HorizontalAlignment.CENTER; + smallButton._T = 1; + smallButton._J = 1; + GREEN_BUTTON = new Component<>(smallButton); + RED_BUTTON = new Component<>(smallButton); + BACK_BUTTON = new Component<>(BIG_BUTTON); + CHAT_BUTTON = new Component<>(smallButton); + CHAT_FILTER_BUTTON = new Component<>(smallButton); + GAMEOPT_BUTTON = new Component<>(smallButton); + smallButton.nineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "smallbutton")); + smallButton.mouseOverNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "smallbutton_mouseover")); + smallButton.mouseHeldNineSliceSprites = smallButton.activeNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "smallbutton_active")); + smallButton.disabledNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "smallbutton_disabled")); + MEDIUM_BUTTON.nineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "mediumbutton")); + MEDIUM_BUTTON.mouseOverNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "mediumbutton_mouseover")); + MEDIUM_BUTTON.mouseHeldNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "mediumbutton_mouseheld")); + BIG_BUTTON.nineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "bigbutton")); + BIG_BUTTON.mouseOverNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "bigbutton_mouseover")); + BIG_BUTTON.mouseHeldNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "bigbutton_mouseheld")); + BIG_BUTTON.disabledNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "bigbutton_disabled")); + GREEN_BUTTON.nineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "greenbutton")); + GREEN_BUTTON.mouseOverNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "greenbutton_mouseover")); + GREEN_BUTTON.mouseHeldNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "greenbutton_mouseheld")); + RED_BUTTON.nineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "redbutton")); + RED_BUTTON.mouseOverNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "redbutton_mouseover")); + RED_BUTTON.mouseHeldNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "redbutton_mouseheld")); + BACK_BUTTON.nineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "backbutton")); + BACK_BUTTON.mouseOverNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "backbutton_mouseover")); + BACK_BUTTON.mouseHeldNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "backbutton_mouseheld")); + BACK_BUTTON.disabledNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "backbutton_disabled")); + GAMEOPT_BUTTON.nineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "gameoptionbutton")); + GAMEOPT_BUTTON.mouseOverNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "gameoptionbutton_mouseover")); + GAMEOPT_BUTTON.mouseHeldNineSliceSprites = GAMEOPT_BUTTON.activeNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "gameoptionbutton_active")); + GAMEOPT_BUTTON.disabledNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "gameoptionbutton_disabled")); + CHAT_BUTTON.nineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "chatbutton")); + CHAT_BUTTON.mouseOverNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "chatbutton_mouseover")); + CHAT_BUTTON.mouseHeldNineSliceSprites = CHAT_BUTTON.activeNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "chatbutton_active")); + CHAT_FILTER_BUTTON.nineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "chatfilterbutton")); + CHAT_FILTER_BUTTON.mouseOverNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "chatfilterbutton_mouseover")); + CHAT_FILTER_BUTTON.mouseHeldNineSliceSprites = CHAT_FILTER_BUTTON.activeNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "chatfilterbutton_active")); + + final Sprite[] checkboxSprites = SpriteResource.loadSprites(spriteLoader, "lobby", "checkbox"); + CHECKBOX = new Checkbox(checkboxSprites[1], checkboxSprites[0], UNSELECTED_LABEL); + + final Component slideRegion = new Component<>(null); + slideRegion.nineSliceSprites = centerOnly(SpriteResource.loadSprite(spriteLoader, "lobby", "slideregion")); + slideRegion.mouseOverNineSliceSprites = centerOnly(SpriteResource.loadSprite(spriteLoader, "lobby", "slideregion_mouseover")); + slideRegion.mouseHeldNineSliceSprites = centerOnly(SpriteResource.loadSprite(spriteLoader, "lobby", "slideregion_mouseheld")); + slideRegion.disabledNineSliceSprites = centerOnly(SpriteResource.loadSprite(spriteLoader, "lobby", "slideregion_disabled")); + final Component dragBar = new Component<>(null); + dragBar.nineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "dragbar")); + dragBar.mouseOverNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "dragbar_mouseover")); + dragBar.mouseHeldNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "dragbar_mouseheld")); + dragBar.disabledNineSliceSprites = adjustForNineSlice(SpriteResource.loadSprites(spriteLoader, "lobby", "dragbar_disabled")); + final Component upButton = new Component<>(null); + upButton.sprite = SpriteResource.loadSprite(spriteLoader, "lobby", "upbutton"); + upButton.mouseOverSprite = SpriteResource.loadSprite(spriteLoader, "lobby", "upbutton_mouseover"); + upButton.mouseHeldSprite = SpriteResource.loadSprite(spriteLoader, "lobby", "upbutton_mouseheld"); + upButton.disabledSprite = SpriteResource.loadSprite(spriteLoader, "lobby", "upbutton_disabled"); + final Component downButton = new Component<>(null); + downButton.sprite = SpriteResource.loadSprite(spriteLoader, "lobby", "downbutton"); + downButton.mouseOverSprite = SpriteResource.loadSprite(spriteLoader, "lobby", "downbutton_mouseover"); + downButton.mouseHeldSprite = SpriteResource.loadSprite(spriteLoader, "lobby", "downbutton_mouseheld"); + downButton.disabledSprite = SpriteResource.loadSprite(spriteLoader, "lobby", "downbutton_disabled"); + SCROLL_BAR = new ScrollBar(upButton, downButton, slideRegion, dragBar); + PLAYER_LIST = new PlayerList(null, null, SCROLL_BAR, smallButton, null, null); + } + + private static void a958tb(final ResourceLoader var4, final @NotNull Sprite[][] gameoptSprites) { + ClientLobbyRoom.WHO_CAN_JOIN_OPTION_SPRITES = SpriteResource.loadSprites(var4, "lobby", "gameprivacy"); + ClientLobbyRoom.RATED_GAME_SPRITES = SpriteResource.loadSprites(var4, "lobby", "ratedgame"); + ClientLobbyRoom.OPEN_TO_ME_SPRITES = SpriteResource.loadSprites(var4, "lobby", "opentome"); + ClientLobbyRoom.ALLOW_SPECTATORS_SPRITES = SpriteResource.loadSprites(var4, "lobby", "allowspectators"); + + ClientLobbyRoom.WHO_CAN_JOIN_OPTION_TOOLTIPS = new String[5]; + ClientLobbyRoom.WHO_CAN_JOIN_OPTION_TOOLTIPS[0] = StringConstants.MULTICONST_INVITE_ONLY; + ClientLobbyRoom.WHO_CAN_JOIN_OPTION_TOOLTIPS[1] = StringConstants.MULTICONST_CLAN; + ClientLobbyRoom.WHO_CAN_JOIN_OPTION_TOOLTIPS[2] = StringConstants.MULTICONST_FRIENDS; + ClientLobbyRoom.WHO_CAN_JOIN_OPTION_TOOLTIPS[3] = StringConstants.MULTICONST_SIMILAR_RATING; + ClientLobbyRoom.WHO_CAN_JOIN_OPTION_TOOLTIPS[4] = StringConstants.MULTICONST_OPEN; + + INVITE_PLAYER_LIST_PANEL = new Component<>(null); + INVITE_PLAYER_LIST_HEADING_NAME = new Component<>(COLUMN_HEADING_MEDIUM_LEFT, StringConstants.MU_LOBBY_NAME); + INVITE_PLAYER_LIST_HEADING_RATING = new Component<>(COLUMN_HEADING_MEDIUM_RIGHT, StringConstants.MU_LOBBY_RATING); + INVITE_PLAYER_LIST_SCROLL_PANE = new ScrollPane<>(new Component<>(null), null, SCROLL_BAR); + INVITE_PLAYER_LIST_PANEL.addChild(INVITE_PLAYER_LIST_HEADING_NAME); + INVITE_PLAYER_LIST_PANEL.addChild(INVITE_PLAYER_LIST_HEADING_RATING); + INVITE_PLAYER_LIST_PANEL.addChild(INVITE_PLAYER_LIST_SCROLL_PANE); + INVITE_PLAYER_LIST_SCROLL_PANE.viewport.copyAttributesFrom(LABEL); + INVITE_PLAYER_LIST_SCROLL_PANE.viewport.verticalAlignment = Font.VerticalAlignment.MIDDLE; + INVITE_PLAYER_LIST_SCROLL_PANE.viewport.textAlignment = Font.HorizontalAlignment.CENTER; + + YOUR_RATING_LABEL = new Component<>(LABEL); + YOUR_RATING_LABEL.textAlignment = Font.HorizontalAlignment.CENTER; + RETURN_TO_MAIN_MENU_BUTTON = new Component<>(BACK_BUTTON, StringConstants.RETURN_TO_MAIN_MENU.toUpperCase()); + ALL_GAMES_HEADING = new Component<>(HEADING, StringConstants.MU_GAMELIST_ALL_GAMES.toUpperCase()); + GAME_LIST_PANEL = new Component<>(_rsEb); + GAME_LIST_HEADING_STATUS = new Component<>(COLUMN_HEADING_MEDIUM_LEFT, StringConstants.STATUS); + GAME_LIST_HEADING_OWNER = new Component<>(COLUMN_HEADING_MEDIUM_CENTER, StringConstants.MU_GAMELIST_OWNER); + GAME_LIST_HEADING_PLAYERS = new Component<>(COLUMN_HEADING_MEDIUM_CENTER, StringConstants.MU_GAMELIST_PLAYERS); + GAME_LIST_HEADING_AVG_RATING = new Component<>(COLUMN_HEADING_MEDIUM_CENTER, StringConstants.MU_GAMELIST_AVG_RATING); + GAME_LIST_HEADING_OPTIONS = new Component<>(COLUMN_HEADING_MEDIUM_CENTER, StringConstants.MU_GAMELIST_OPTIONS); + GAME_LIST_HEADING_ELAPSED_TIME = new Component<>(COLUMN_HEADING_MEDIUM_RIGHT, StringConstants.MU_GAMELIST_ELAPSED_TIME); + GAME_LIST_SCROLL_PANE = new ScrollPane<>(new Component<>(null), null, SCROLL_BAR); + PLAY_RATED_GAME_BUTTON = new Component<>(BIG_BUTTON, StringConstants.MU_PLAY_RATED.toUpperCase()); + PLAY_RATED_GAME_BUTTON.enabled = true; + CREATE_UNRATED_GAME_BUTTON = new Component<>(BIG_BUTTON, (StringConstants.MU_CREATE_UNRATED).toUpperCase()); + LOBBY_RIGHT_PANEL = new Component<>(null); + LOBBY_RIGHT_PANEL.addChild(ALL_GAMES_HEADING); + LOBBY_RIGHT_PANEL.addChild(GAME_LIST_PANEL); + GAME_LIST_PANEL.addChild(GAME_LIST_HEADING_STATUS); + GAME_LIST_PANEL.addChild(GAME_LIST_HEADING_OWNER); + GAME_LIST_PANEL.addChild(GAME_LIST_HEADING_PLAYERS); + GAME_LIST_PANEL.addChild(GAME_LIST_HEADING_AVG_RATING); + GAME_LIST_PANEL.addChild(GAME_LIST_HEADING_OPTIONS); + GAME_LIST_PANEL.addChild(GAME_LIST_HEADING_ELAPSED_TIME); + GAME_LIST_PANEL.addChild(GAME_LIST_SCROLL_PANE); + LOBBY_RIGHT_PANEL.addChild(PLAY_RATED_GAME_BUTTON); + LOBBY_RIGHT_PANEL.addChild(CREATE_UNRATED_GAME_BUTTON); + YOU_HAVE_BEEN_KICKED_LABEL = new Component<>(LABEL); + YOU_HAVE_BEEN_KICKED_LABEL.verticalAlignment = Font.VerticalAlignment.TOP; + YOU_HAVE_BEEN_KICKED_LABEL.textAlignment = Font.HorizontalAlignment.CENTER; + YOU_HAVE_BEEN_KICKED_OK_BUTTON = new Component<>(MEDIUM_BUTTON, StringConstants.OK.toUpperCase()); + YOU_HAVE_BEEN_KICKED_DIALOG = new Component<>(null); + YOU_HAVE_BEEN_KICKED_DIALOG.addChild(YOU_HAVE_BEEN_KICKED_LABEL); + YOU_HAVE_BEEN_KICKED_DIALOG.addChild(YOU_HAVE_BEEN_KICKED_OK_BUTTON); + RATED_GAME_TIPS_LABEL = new Component<>(null); + RATED_GAME_TIPS_LABEL.copyAttributesFrom(LABEL); + RATED_GAME_TIPS_LABEL.verticalAlignment = Font.VerticalAlignment.MIDDLE; + RATED_GAME_TIPS_LABEL.textAlignment = Font.HorizontalAlignment.CENTER; + JOINED_PLAYERS_PANEL = new Component<>(null); + JOINED_PLAYER_COUNT_LABEL = new Component<>(LABEL); + JOINED_PLAYER_COUNT_LABEL.textAlignment = Font.HorizontalAlignment.CENTER; + NAME_LABEL = new Component<>(COLUMN_HEADING_MEDIUM_LEFT, StringConstants.MU_LOBBY_NAME); + RATING_LABEL = new Component<>(COLUMN_HEADING_MEDIUM_RIGHT, StringConstants.MU_LOBBY_RATING); + JOINED_PLAYERS_TABLE = new ScrollPane<>(new Component<>(null), null, SCROLL_BAR); + JOINED_PLAYERS_PANEL.addChild(JOINED_PLAYER_COUNT_LABEL); + JOINED_PLAYERS_PANEL.addChild(NAME_LABEL); + JOINED_PLAYERS_PANEL.addChild(RATING_LABEL); + JOINED_PLAYERS_PANEL.addChild(JOINED_PLAYERS_TABLE); + RETURN_TO_LOBBY_BUTTON = new Component<>(BACK_BUTTON, StringConstants.RETURN_TO_LOBBY.toUpperCase()); + GAME_OWNER_HEADING = new Component<>(HEADING); + GAME_OPTIONS_CONTAINER = new Component<>(_rsEb); + + GAME_OPTIONS_HEADING = new Component<>(COLUMN_HEADING_LARGE, StringConstants.MU_OPTIONS.toUpperCase()); + GAME_OPTIONS_LABELS = new Component[9]; + GAME_OPTIONS_BUTTONS = new ActionButton[9][]; + + GAME_OPTIONS_LABELS[0] = new Component<>(LABEL_DARK_2, StringConstants.MU_OPTIONS_WHO_CAN_JOIN); + GAME_OPTIONS_BUTTONS[0] = new ActionButton[6]; + for (int i = 0; i < 5; ++i) { + GAME_OPTIONS_BUTTONS[0][i + 1] = new ActionButton(GAMEOPT_BUTTON, UNSELECTED_LABEL, ClientLobbyRoom.WHO_CAN_JOIN_OPTION_SPRITES[i], ClientLobbyRoom.WHO_CAN_JOIN_OPTION_TOOLTIPS[i]); + } + + GAME_OPTIONS_LABELS[1] = new Component<>(LABEL_DARK_2, StringConstants.MU_OPTIONS_PLAYERS); + GAME_OPTIONS_BUTTONS[1] = new ActionButton[1 + ShatteredPlansClient.NUM_PLAYERS_OPTION_VALUES.length]; + GAME_OPTIONS_BUTTONS[1][0] = new ActionButton(GAMEOPT_BUTTON, UNSELECTED_LABEL, null, StringConstants.MU_OPTIONS_DONT_MIND); + for (int i = 0; i < ShatteredPlansClient.NUM_PLAYERS_OPTION_VALUES.length; ++i) { + GAME_OPTIONS_BUTTONS[1][i + 1] = new ActionButton(GAMEOPT_BUTTON, UNSELECTED_LABEL, null, Integer.toString(ShatteredPlansClient.NUM_PLAYERS_OPTION_VALUES[i])); + } + + GAME_OPTIONS_LABELS[2] = new Component<>(LABEL_DARK_2, StringConstants.MU_OPTIONS_ALLOW_SPECTATE); + GAME_OPTIONS_BUTTONS[2] = new ActionButton[]{ + new ActionButton(GAMEOPT_BUTTON, UNSELECTED_LABEL, null, StringConstants.MU_OPTIONS_DONT_MIND), + new ActionButton(GAMEOPT_BUTTON, UNSELECTED_LABEL, ClientLobbyRoom.ALLOW_SPECTATORS_SPRITES[0], StringConstants.NO), + new ActionButton(GAMEOPT_BUTTON, UNSELECTED_LABEL, ClientLobbyRoom.ALLOW_SPECTATORS_SPRITES[1], StringConstants.YES) + }; + + for (int i = 0; i < 5; ++i) { + GAME_OPTIONS_LABELS[i + 4] = new Component<>(LABEL_DARK_2, StringConstants.GAMEOPT_LABELS[i]); + GAME_OPTIONS_BUTTONS[i + 4] = new ActionButton[ShatteredPlansClient.GAMEOPT_CHOICES_COUNTS[i] + 1]; + GAME_OPTIONS_BUTTONS[i + 4][0] = new ActionButton(GAMEOPT_BUTTON, UNSELECTED_LABEL, null, StringConstants.MU_OPTIONS_DONT_MIND); + + for (int j = 0; j < ShatteredPlansClient.GAMEOPT_CHOICES_COUNTS[i]; ++j) { + final Sprite sprites = gameoptSprites[i] != null ? gameoptSprites[i][j] : null; + final String tooltip = StringConstants.GAMEOPT_NAMES[i] != null ? StringConstants.GAMEOPT_NAMES[i][j] : null; + GAME_OPTIONS_BUTTONS[i + 4][j + 1] = new ActionButton(GAMEOPT_BUTTON, UNSELECTED_LABEL, sprites, tooltip); + } + } + + for (int i = 0; i < 9; ++i) { + if (GAME_OPTIONS_LABELS[i] != null) { + GAME_OPTIONS_LABELS[i]._Y = 11; + } + + if (GAME_OPTIONS_BUTTONS[i] != null) { + for (int j = 0; j < GAME_OPTIONS_BUTTONS[i].length; ++j) { + if (GAME_OPTIONS_BUTTONS[i][j] != null && GAME_OPTIONS_BUTTONS[i][j]._Bb != null) { + GAME_OPTIONS_BUTTONS[i][j]._Bb._Y = 11; + } + } + } + } + + INVITE_PLAYERS_BUTTON = new Component<>(BIG_BUTTON); + FIND_OPPONENTS_BUTTON = new Component<>(BIG_BUTTON); + WAITING_TO_START_LABEL = new Component<>(LABEL_DARK_1); + WAITING_TO_START_LABEL.copyAttributesFrom(LABEL); + WAITING_TO_START_LABEL.verticalAlignment = Font.VerticalAlignment.MIDDLE; + WAITING_TO_START_LABEL.textAlignment = Font.HorizontalAlignment.CENTER; + GAME_INFO_CONTAINER = new Component<>(null); + GAME_INFO_CONTAINER.addChild(GAME_OWNER_HEADING); + GAME_INFO_CONTAINER.addChild(GAME_OPTIONS_CONTAINER); + GAME_OPTIONS_CONTAINER.addChild(GAME_OPTIONS_HEADING); + + for (int i = 0; i < 4 + 5; ++i) { + if (i != 3) { + GAME_OPTIONS_CONTAINER.addChild(GAME_OPTIONS_LABELS[i]); + for (int j = 0; j < GAME_OPTIONS_BUTTONS[i].length; ++j) { + if (GAME_OPTIONS_BUTTONS[i][j] != null) { + GAME_OPTIONS_CONTAINER.addChild(GAME_OPTIONS_BUTTONS[i][j]); + } + } + } + } + + GAME_INFO_CONTAINER.addChild(INVITE_PLAYERS_BUTTON); + GAME_INFO_CONTAINER.addChild(FIND_OPPONENTS_BUTTON); + GAME_INFO_CONTAINER.addChild(WAITING_TO_START_LABEL); + INVITE_PLAYERS_LABEL = new Component<>(TAB_ACTIVE, StringConstants.MU_INVITE_PLAYERS.toUpperCase()); + CLOSE_BUTTON_2 = new Component<>(MEDIUM_BUTTON, StringConstants.CLOSE.toUpperCase()); + } + + private static void initializeChatResources(final ResourceLoader var2) { + initializeChatResources1(); + CHAT_FILTER_SPRITES = SpriteResource.loadSprites(var2, "lobby", "chatfilter"); + CHAT_FILTER_LABELS[0] = StringConstants.MU_CHAT_ON; + CHAT_FILTER_LABELS[1] = StringConstants.MU_CHAT_FRIENDS; + CHAT_FILTER_LABELS[2] = StringConstants.MU_CHAT_OFF; + initializeQuickChatResources(); + } + + private static void initializeQuickChatResources() { + _uaf = new Component<>(null); + if (ResourceLoader.QUICK_CHAT_DATA == null) { + JagexApplet.clientError(null, "QC1"); + return; + } + + ResourceLoader.QUICK_CHAT_DATA.releaseItemsOnGet = false; + ResourceLoader.QUICK_CHAT_DATA.releaseGroupsOnGet = false; + _guiA = new QuickChatCategories(ResourceLoader.QUICK_CHAT_DATA); + JagexApplet._dhc = new QuickChatResponses(ResourceLoader.QUICK_CHAT_DATA); + final QuickChatCategory var4 = a528hc(); + if (var4 == null) { + JagexApplet.clientError(null, "QC2"); + return; + } + + a857ke(var4); + ReportAbuseDialog._Nb = a658rd(65793, 5138823, 65793, 65793, 4020342, 1127256, 1513239, null, 0, 2245737, 1513239, 8947848); + _nld = a658rd(0, 0, 0, 0, 0, 0, 0, GENERAL_FONT, 16764006, 0, 0, 0); + _hlI = a658rd(0, 0, 0, 0, 0, 0, 0, GENERAL_FONT, Drawing.WHITE, 0, 0, 0); + + final int var5 = Drawing.width; + final int var6 = Drawing.height; + final int[] var7 = Drawing.screenBuffer; + vm_._kflc = new Sprite(10, 14); + vm_._kflc.installForDrawing(); + + for (int var8 = 2; var8 < 7; ++var8) { + Drawing.verticalLine(var8, var8 + 1, -(var8 << 1) + 14, Drawing.WHITE); + } + + Drawing.initialize(var7, var5, var6); + _ofb = a427gn(var4, _hlI, _nld, ReportAbuseDialog._Nb); + _uaf.children = new ArrayList<>(); + } + + private static void initializeChatResources1() { + CHANNEL_TEXT_COLORS_1[0] = 0xffcc60; + CHANNEL_TEXT_COLORS_1[1] = 0x60ff60; + CHANNEL_TEXT_COLORS_1[2] = 0x9090ff; + CHANNEL_TEXT_COLORS_1[3] = 0xff60ff; + CHANNEL_TEXT_COLORS_1[4] = 0xff00ff; + + CHANNEL_TEXT_COLORS_2[0] = 0xffcc60; + CHANNEL_TEXT_COLORS_2[1] = 0x60ff60; + CHANNEL_TEXT_COLORS_2[2] = 0xff6060; + CHANNEL_TEXT_COLORS_2[3] = 0xff60ff; + + final Sprite hatching = new Sprite(4, 4); + hatching.pixels[2] = 0x707070; + hatching.pixels[5] = 0x707070; + hatching.pixels[8] = 0x707070; + hatching.pixels[15] = 0x707070; + + _tgc = new Component<>(_cna); + _adc = new Component<>(_mpa); + _tgc.addChild(_adc); + final Component> var16 = new Component<>(null); + var16.children = new ArrayList<>(); + _jiI = new ScrollPane<>(var16, LABEL_DARK_2, SCROLL_BAR); + _adc.addChild(_jiI); + _taio = new Component<>(LABEL_DARK_1); + _adc.addChild(_taio); + ShatteredPlansClient.chatMessageLabel = new Component<>(LABEL); + ShatteredPlansClient.chatMessageLabel.font = CHAT_FONT; + _taio.addChild(ShatteredPlansClient.chatMessageLabel); + _taio.recursivelySet_H(); + _cgC = new Component<>(null); + _cgC.nineSliceSprites = new Sprite[9]; + _cgC.nineSliceSprites[NineSliceSprite.CENTER] = hatching; + _taio.addChild(_cgC); + chatFilterIcons = new Component[5]; + chatFilterChannelLabels = new Component[5]; + chatFilterLabels = new Component[5]; + //noinspection unchecked + chatFilterButtons = new Component[5]; + + for (final ChatMessage.Channel channel : ChatMessage.Channel.values()) { + final String channelName; + if (channel == ChatMessage.Channel.LOBBY) { + channelName = StringConstants.MU_CHAT_LOBBY; + } else if (channel == ChatMessage.Channel.ROOM) { + channelName = StringConstants.MU_CHAT_GAME; + } else if (channel == ChatMessage.Channel.PRIVATE) { + channelName = StringConstants.MU_CHAT_PRIVATE; + } else { + continue; + } + + final int i = channel.ordinal(); + chatFilterButtons[i] = new Component<>(CHAT_FILTER_BUTTON); + chatFilterChannelLabels[i] = new Component<>(UNSELECTED_LABEL, channelName); + chatFilterIcons[i] = new Component<>(null); + chatFilterIcons[i].verticalAlignment = Font.VerticalAlignment.MIDDLE; + chatFilterLabels[i] = new Component<>(UNSELECTED_LABEL); + chatFilterLabels[i].verticalAlignment = Font.VerticalAlignment.MIDDLE; + chatFilterButtons[i].addChild(chatFilterChannelLabels[i]); + chatFilterButtons[i].addChild(chatFilterIcons[i]); + chatFilterButtons[i].addChild(chatFilterLabels[i]); + chatFilterButtons[i].recursivelySet_H(); + _tgc.addChild(chatFilterButtons[i]); + ++chatFilterButtonCount; + } + + _a = new Component<>(CHAT_BUTTON); + _a.label = StringConstants.REPORT_ABUSE; + _tgc.addChild(_a); + if (!JagexApplet.connectedAndLoggedIn() || JagexApplet.cannotChat) { + DobToEnableChatForm.instance = new DobToEnableChatForm(); + } + } + + private static void initializeRuleStrings() { + ReportAbuseDialog.RULE_STRINGS = new String[22]; + ReportAbuseDialog.RULE_STRINGS[ 4] = StringConstants.RULE_0_5; + ReportAbuseDialog.RULE_STRINGS[ 5] = StringConstants.RULE_0_2; + ReportAbuseDialog.RULE_STRINGS[ 6] = StringConstants.RULE_0_0; + ReportAbuseDialog.RULE_STRINGS[ 7] = StringConstants.RULE_0_3; + ReportAbuseDialog.RULE_STRINGS[ 9] = StringConstants.RULE_0_1; + ReportAbuseDialog.RULE_STRINGS[11] = StringConstants.RULE_2_2; + ReportAbuseDialog.RULE_STRINGS[13] = StringConstants.RULE_2_0; + ReportAbuseDialog.RULE_STRINGS[15] = StringConstants.RULE_0_4; + ReportAbuseDialog.RULE_STRINGS[16] = StringConstants.RULE_1_0; + ReportAbuseDialog.RULE_STRINGS[17] = StringConstants.RULE_1_1; + ReportAbuseDialog.RULE_STRINGS[18] = StringConstants.RULE_1_2; + ReportAbuseDialog.RULE_STRINGS[19] = StringConstants.RULE_1_3; + ReportAbuseDialog.RULE_STRINGS[20] = StringConstants.RULE_1_4; + ReportAbuseDialog.RULE_STRINGS[21] = StringConstants.RULE_2_1; + } + + private static void a460bq(final ResourceLoader loader) { + DISPLAY_NAME_CHANGED = SpriteResource.loadSprite(loader, "basic", "display_name_changed"); + FRIEND_LIST = new PlayerList(PLAYER_LIST, StringConstants.MU_LOBBY_FRIEND_ADD, StringConstants.MU_LOBBY_FRIEND_RM); + IGNORE_LIST = new PlayerList(PLAYER_LIST, StringConstants.MU_LOBBY_NAME_ADD, StringConstants.MU_LOBBY_NAME_RM); + FRIEND_LIST_PANEL = new Component<>(null); + SERVER_INFO_LABEL = new Component<>(LABEL); + SERVER_INFO_LABEL.textAlignment = Font.HorizontalAlignment.CENTER; + NAME_LABEL_2 = new Component<>(COLUMN_HEADING_MEDIUM_LEFT, StringConstants.MU_LOBBY_NAME); + LOCATION_LABEL = new Component<>(COLUMN_HEADING_MEDIUM_RIGHT, StringConstants.MU_LOBBY_LOCATION); + FRIEND_LIST_PANEL.addChild(SERVER_INFO_LABEL); + FRIEND_LIST_PANEL.addChild(NAME_LABEL_2); + FRIEND_LIST_PANEL.addChild(LOCATION_LABEL); + FRIEND_LIST_PANEL.addChild(FRIEND_LIST); + FRIEND_LIST_PANEL.addChild(new Component<>(UNSELECTED_LABEL)); + + FRIEND_LIST.scrollPane.viewport.copyAttributesFrom(LABEL); + FRIEND_LIST.scrollPane.viewport.verticalAlignment = Font.VerticalAlignment.MIDDLE; + FRIEND_LIST.scrollPane.viewport.textAlignment = Font.HorizontalAlignment.CENTER; + IGNORE_LIST.scrollPane.viewport.copyAttributesFrom(LABEL); + IGNORE_LIST.scrollPane.viewport.verticalAlignment = Font.VerticalAlignment.MIDDLE; + IGNORE_LIST.scrollPane.viewport.textAlignment = Font.HorizontalAlignment.CENTER; + } + + private static Component a658rd(final int var0, final int var1, final int var2, final int var3, final int var4, final int var6, final int var7, final Font var8, final int var9, final int var10, final int var11, final int var12) { + final Component var13 = new Component<>(null); + var13.nineSliceSprites = a130cr(var7, var3); + var13.mouseOverNineSliceSprites = a130cr(var12, var11); + var13.mouseHeldNineSliceSprites = a130cr(var10, var6); + var13.activeNineSliceSprites = a130cr(var1, var4); + var13.disabledNineSliceSprites = a130cr(var0, var2); + var13.font = var8; + var13.textColor = var9; + return var13; + } + + private static Sprite[] a130cr(final int var0, final int var3) { + final Sprite[] var4 = new Sprite[9]; + var4[0] = funorb.commonui.Component.createSolidSquareSprite(1, var3); + + for (int var5 = 1; var5 < 9; ++var5) { + var4[var5] = var4[0]; + } + + var4[4] = funorb.commonui.Component.createSolidSquareSprite(64, var0); + return var4; + } + + private static void a487te() { + ShatteredPlansClient.a150bq(); + a669hr(CHAT_FILTER_SPRITES[0].offsetX, ShatteredPlansClient._tga, _rcl); + } + + private static void a857ke(final QuickChatCategory var1) { + var1._s = new char[]{'?'}; + var1._x = new int[]{-1}; + } + + private static Sprite[] createColumnHeadingSprites(final int height, final int color2, final int color1, final boolean roundTopLeft, final boolean roundTopRight) { + final int[] oldBuffer = Drawing.screenBuffer; + final int oldWidth = Drawing.width; + final int oldHeight = Drawing.height; + final Sprite center = new Sprite(16, height); + center.installForDrawing(); + Drawing.fillRectangleVerticalGradient(0, 0, 16, height, color1, color2); + final Sprite left; + if (roundTopLeft) { + left = center.copy(); + left.installForDrawing(); + Drawing.horizontalLine(0, 0, 5, 0); + Drawing.horizontalLine(0, 1, 3, 0); + Drawing.horizontalLine(0, 2, 2, 0); + Drawing.horizontalLine(0, 3, 1, 0); + Drawing.horizontalLine(0, 4, 1, 0); + } else { + left = null; + } + + final Sprite right; + if (roundTopRight) { + right = center.copy(); + right.installForDrawing(); + Drawing.horizontalLine(11, 0, 5, 0); + Drawing.horizontalLine(13, 1, 3, 0); + Drawing.horizontalLine(14, 2, 2, 0); + Drawing.horizontalLine(15, 3, 1, 0); + Drawing.horizontalLine(15, 4, 1, 0); + } else { + right = null; + } + + Drawing.initialize(oldBuffer, oldWidth, oldHeight); + return new Sprite[]{null, null, null, left, center, right, null, null, null}; + } + + public static void initializeLobbyBrowserComponents() { + lobbyBrowserPlayerList = new Component<>(null); + lobbyBrowserPlayerList.addChild(YOUR_RATING_LABEL); + lobbyBrowserPlayerList.addChild(INVITE_PLAYER_LIST_PANEL); + lobbyBrowserTabbedPlayerList = new TabbedPlayerListWrapper(StringConstants.MU_CHAT_LOBBY, lobbyBrowserPlayerList); + lobbyBrowserLeftPanel = new Component<>(null); + lobbyBrowserLeftPanel.addChild(lobbyBrowserTabbedPlayerList.view); + lobbyBrowserLeftPanel.addChild(RETURN_TO_MAIN_MENU_BUTTON); + layoutLobbyBrowser(); + } + + public static void layoutLobbyBrowser() { + lastLayoutHeight = Drawing.height; + lastLayoutWidth = Drawing.width; + layoutLobbyBrowserPanels(); + lobbyBrowserTabbedPlayerList.updateBounds(lobbyBrowserLeftPanel.width, lobbyBrowserLeftPanel.height - 42); + YOUR_RATING_LABEL.setBounds(0, 0, lobbyBrowserPlayerList.width, LABEL_HEIGHT); + final int var1 = LABEL_HEIGHT + 2; + INVITE_PLAYER_LIST_PANEL.setBounds(0, var1, lobbyBrowserPlayerList.width, lobbyBrowserPlayerList.height - (var1)); + ShatteredPlansClient.d150p(); + RETURN_TO_MAIN_MENU_BUTTON.setBounds(0, lobbyBrowserLeftPanel.height - 40, lobbyBrowserLeftPanel.width, 40); + ALL_GAMES_HEADING.setBounds(0, 0, LOBBY_RIGHT_PANEL.width, 30); + GAME_LIST_PANEL.setBounds(0, 30, LOBBY_RIGHT_PANEL.width, LOBBY_RIGHT_PANEL.height - 40 - 32); + GAME_LIST_HEADING_STATUS.setBounds(5, 5, 68, 30); + GAME_LIST_HEADING_OWNER.setBounds(75, 5, 78, 30); + GAME_LIST_HEADING_PLAYERS.setBounds(155, 5, 48, 30); + GAME_LIST_HEADING_AVG_RATING.setBounds(205, 5, 48, 30); + GAME_LIST_HEADING_OPTIONS.setBounds(255, 5, 113, 30); + GAME_LIST_HEADING_ELAPSED_TIME.setBounds(370, 5, LOBBY_RIGHT_PANEL.width - 5 - 370, 30); + //noinspection SuspiciousNameCombination + GAME_LIST_SCROLL_PANE.setBounds(5, 37, GAME_LIST_PANEL.width - 5 - 5, GAME_LIST_PANEL.height - 32 - 5 - 5, LABEL_HEIGHT); + + final int var3 = (LOBBY_RIGHT_PANEL.width + 2) / 2; + PLAY_RATED_GAME_BUTTON.setBounds(0, LOBBY_RIGHT_PANEL.height - 40, var3 - 2, 40); + CREATE_UNRATED_GAME_BUTTON.setBounds(var3, LOBBY_RIGHT_PANEL.height - 40, LOBBY_RIGHT_PANEL.width - var3, 40); + } + + public static void layoutLobbyBrowserPanels() { + final int var1 = (lastLayoutWidth - ShatteredPlansClient.SCREEN_WIDTH) / 2; + final int var2 = 400; + final int var3 = var2 - ShatteredPlansClient.lobbyBrowserTransitionCounter * ShatteredPlansClient.lobbyBrowserTransitionCounter; + lobbyBrowserLeftPanel.setBounds(var1 - (199 * var3 / var2), 90, 199, Drawing.height - 90 - 124); + LOBBY_RIGHT_PANEL.setBounds(var1 + 202 + var3 * 438 / var2, 0, 438, Drawing.height - 124); + } + + private static Sprite[] adjustForNineSlice(final Sprite[] sprites) { + for (final Sprite sprite : sprites) { + sprite.x = 0; + sprite.y = 0; + sprite.offsetX = sprite.width; + sprite.offsetY = sprite.height; + } + + return sprites; + } + + private static QuickChatCategory a528hc() { + try { + int var1 = 0; + while (true) { + final QuickChatCategory var2 = _guiA.get(var1); + if (var2._y) { + return var2; + } + + ++var1; + } + } catch (final IllegalArgumentException var3) { + return null; + } + } + + private static Sprite[] centerOnly(final Sprite sprite) { + final Sprite[] sprites = new Sprite[9]; + sprites[NineSliceSprite.CENTER] = sprite; + return sprites; + } + + private static vm_ a427gn(final QuickChatCategory var1, final Component var2, final Component var3, final Component var4) { + if (var1 == null) { + return null; + } else { + final int var5 = var1._r == null ? 0 : var1._r.length; + final int var6 = var1._x != null ? var1._x.length : 0; + final int var7 = var5 + var6; + final String[] var8 = new String[var7]; + final char[] var9 = new char[var7]; + final int[] var10 = new int[var7]; + final vm_[] var11 = new vm_[var7]; + int var12; + if (var1._r != null) { + for (var12 = 0; var12 < var1._r.length; ++var12) { + final QuickChatCategory var13 = _guiA.get(var1._r[var12]); + var8[var12] = var13.name; + var9[var12] = var1._p[var12]; + var11[var12] = a427gn(var13, var2, var3, var4); + } + } + + if (var1._x != null) { + var12 = var5; + char var17 = '1'; + + for (int var14 = 0; var14 < var1._x.length; ++var14) { + final int var15 = var1._x[var14]; + if (var15 == -1) { + var8[var12 + var14] = StringConstants.QUICK_CHAT_HELP; + var9[var12 + var14] = var1._s[var14]; + } else { + final QuickChatResponse var16 = JagexApplet._dhc.get(var15); + var8[var14 + var12] = var16.joinStrings(); + var9[var12 + var14] = var1._s[var14]; + if (var9[var12 + var14] == 0) { + var9[var14 + var12] = var17++; + } + + } + var10[var12 + var14] = var1._x[var14]; + } + } + + return new vm_(var2, var4, var3, var11, var10, var8, var9); + } + } + + private static void a669hr(final int var0, final int var2, final int var4) { + final int var5 = LABEL_HEIGHT + 2 + 485 + 8 + var2 + 8; + _adc.setBounds(3, 3, var5 - 6, _tgc.height - 6); + int var6 = _adc.height - 5; + _taio.setBounds(5, -LABEL_HEIGHT + var6, 487 + var2 + LABEL_HEIGHT, LABEL_HEIGHT); + ShatteredPlansClient.chatMessageLabel.setBounds(var2, 0, -_cgC.width - var2 + _taio.width, LABEL_HEIGHT); + var6 -= LABEL_HEIGHT + 2; + _cgC.setBounds(var2 + ShatteredPlansClient.chatMessageLabel.width, 0, _cgC.width, LABEL_HEIGHT); + //noinspection SuspiciousNameCombination + _jiI.setBounds(5, 5, 485 + var2 - (-17), var6 - 5, LABEL_HEIGHT); + if (DobToEnableChatForm.instance != null) { + DobToEnableChatForm.instance.setBounds(_jiI.x, _jiI.y, _jiI.width, _jiI.height); + } + + final int var7 = -var5 - var2 + _tgc.width; + final int var8 = var7 / 2; + final int var9 = var2 + var0 + var8; + int var10 = 0; + + for (int var11 = 0; var11 < 6; ++var11) { + if (var11 == 5 || chatFilterButtons[var11] != null) { + final int var12 = (_tgc.height - 4) * var10 / (chatFilterButtonCount + 1) + 3; + ++var10; + var6 = -var12 + var10 * (_tgc.height - 4) / (1 + chatFilterButtonCount) + 3 - 2; + if (var11 < 5) { + chatFilterButtons[var11].setBounds(var5, var12, var7, var6); + chatFilterChannelLabels[var11].setBounds(var2, 0, var8 - var2, var6); + chatFilterIcons[var11].setBounds(var8, var4, var0, -var4 + var6 - var4); + chatFilterLabels[var11].setBounds(var9, var4, var7 - var2 - var9, var6 - var4 - var4); + } else { + _a.setBounds(var5, var12, var7, var6); + } + } + } + + } + + public static Sprite[] createGradientOutlineSprites(final int height, final int topColor, final int bottomColor, final int centerColor) { + final int[] oldBuffer = Drawing.screenBuffer; + final int oldWidth = Drawing.width; + final int oldHeight = Drawing.height; + + final Sprite sides = new Sprite(3, height - 6); + sides.installForDrawing(); + Drawing.fillRectangleVerticalGradient(0, 0, 3, height - 6, topColor, bottomColor); + + final Sprite topCorner = new Sprite(3, 3); + topCorner.installForDrawing(); + Drawing.fillRect(0, 0, 3, 3, topColor); + + final Sprite top = new Sprite(16, 3); + top.installForDrawing(); + Drawing.fillRect(0, 0, 16, 3, topColor); + + final Sprite bottomCorner = new Sprite(3, 3); + bottomCorner.installForDrawing(); + Drawing.fillRect(0, 0, 3, 3, bottomColor); + + final Sprite bottom = new Sprite(16, 3); + bottom.installForDrawing(); + Drawing.fillRect(0, 0, 16, 3, bottomColor); + Sprite center = null; + + if (centerColor > 0) { + center = new Sprite(16, 16); + center.installForDrawing(); + Drawing.fillRect(0, 0, 16, 16, centerColor); + } + + Drawing.initialize(oldBuffer, oldWidth, oldHeight); + return new Sprite[]{topCorner, top, topCorner, sides, center, sides, bottomCorner, bottom, bottomCorner}; + } + + protected final int a353(final int var1) { + int var3 = 0; + int var4; + if (this.label != null && this.font != null) { + var4 = this.font.measureParagraphWidth(this.label, var1); + if (var4 > var3) { + var3 = var4; + } + } + + if (this.sprite != null) { + var4 = this.sprite.offsetX; + if (var4 > var3) { + var3 = var4; + } + } + + if (this.children != null) { + for (final Component var6 : this.children) { + final int var5 = var6.x + var6.width; + if (var3 < var5) { + var3 = var5; + } + } + } + + return var3; + } + + public final void addChild(final T child) { + if (this.children == null) { + this.children = new ArrayList<>(); + } + assert !this.children.contains(child); + this.children.add(child); + } + + public final void placeAfter(final Component prev, final Component next) { + if (prev == null) { + next._w = 0; + next.y = 0; + } else { + next.y = prev.height + prev.y + 2; + next._w = prev._w + prev._gb; + } + } + + public final void b540(final boolean var1) { + this.a360(true, false, 0, 0, false, Drawing.height, false, var1, Drawing.width); + } + + protected final void a811(final int var1, final boolean var3) { + int var5 = -this.y; + int var6 = var5 - this._w; + final int var7 = this.height; + int var8 = var7 + this._gb; + int var9; + if (!var3) { + var9 = 0; + + for (final Component var10 : this.children) { + var10._w = -var10.y + var9; + var9 += var10.height + var10._gb + 2; + } + + var8 = -2 + var9; + } + + var9 = var8 - var1; + if (var6 > var9) { + var6 = var9; + } + + if (var6 < 0) { + var6 = 0; + } + + final int var11 = -var1 + var7; + if (var5 > var11) { + var5 = var11; + } + + if (var5 < 0) { + var5 = 0; + } + + this._w = var5 - var6; + this.y = -var5; + this._gb = -var7 + var8; + } + + public final void recursivelySet_H() { + if (this.children != null) { + for (final Component child : this.children) { + child._H = true; + child.recursivelySet_H(); + } + } + } + + private void processMouseEvents(final int var1, final int var2, final int var3, final int var6) { + final int var7; + if (this._cb > 0) { + var7 = -(-this._cb >> 2); + } else { + var7 = this._cb >> 2; + } + this._cb -= var7; + this.x += var7; + + final int var100; + if (this._w <= 0) { + var100 = this._w >> 2; + } else { + var100 = -(-this._w >> 2); + } + this.y += var100; + this._w -= var100; + + final int var101; + if (this._S <= 0) { + var101 = this._S >> 2; + } else { + var101 = -(-this._S >> 2); + } + this.width += var101; + this._S -= var101; + + final int var102; + if (this._gb <= 0) { + var102 = this._gb >> 2; + } else { + var102 = -(-this._gb >> 2); + } + this.height += var102; + this._gb -= var102; + + this.x2 = this.x + var1; + this.y2 = this.y + var2; + final int var9 = Drawing.left; + final int var10 = Drawing.top; + final int var11 = Drawing.right; + final int var12 = Drawing.bottom; + Drawing.expandBoundsToInclude(this.x2, this.y2, this.x2 + this.width, this.y2 + this.height); + boolean clicked = false; + if (!clickConsumed && this.enabled + && JagexApplet.mouseButtonJustClicked != MouseState.Button.NONE + && Drawing.left <= JagexApplet.mousePressX && Drawing.right > JagexApplet.mousePressX + && JagexApplet.mousePressY >= Drawing.top && JagexApplet.mousePressY < Drawing.bottom) { + clicked = true; + this.relativeClickX = JagexApplet.mousePressX - this.x2; + this.relativeClickY = JagexApplet.mousePressY - this.y2; + this.clickButton = JagexApplet.mouseButtonJustClicked; + this.dragButton = JagexApplet.mouseButtonJustClicked; + } else { + if (JagexApplet.mouseButtonJustClicked != MouseState.Button.NONE) { + this.dragButton = MouseState.Button.NONE; + } + this.clickButton = MouseState.Button.NONE; + } + + if (JagexApplet.mouseButtonDown == MouseState.Button.NONE) { + this.dragButton = MouseState.Button.NONE; + } + + this.isMouseOver = !mouseOverConsumed && Drawing.left <= JagexApplet.mouseX && Drawing.right > JagexApplet.mouseX && Drawing.top <= JagexApplet.mouseY && Drawing.bottom > JagexApplet.mouseY; + this.isMouseOverTarget = this.isMouseOver && this.dragButton == JagexApplet.mouseButtonDown && this.enabled; + if (this.children != null) { + for (final ListIterator it = this.children.listIterator(this.children.size()); it.hasPrevious(); ) { + final Component child = it.previous(); + child.processMouseEvents(this.x2, this.y2, this.width, this.height); + } + } + + if (this.isMouseOver) { + mouseOverConsumed = true; + } + if (clicked) { + clickConsumed = true; + } + + Drawing.setBounds(var9, var10, var11, var12); + if (this.isDraggable && this.dragButton != MouseState.Button.NONE) { + this.y = JagexApplet.mouseY - this.relativeClickY - var2; + this.x = JagexApplet.mouseX - this.relativeClickX - var1; + if (this.x < 0) { + this.x = 0; + } + + if (this.x > var3 - this.width) { + this.x = var3 - this.width; + } + + if (this.y < 0) { + this.y = 0; + } + + this._cb = 0; + if (this.y > var6 - this.height) { + this.y = var6 - this.height; + } + + this.x2 = this.x + var1; + this._w = 0; + this.y2 = this.y + var2; + } + } + + private void copyAttributesFrom(final Component var1) { + if (var1 != null) { + if (var1.label != null) { + this.label = var1.label; + } + + if (var1._r) { + this._r = true; + } + + if (var1._Z != null) { + this._Z = var1._Z; + } + + if (!var1.enabled) { + this.enabled = false; + } + + if (var1.selected) { + this.selected = true; + } + + if (var1._kb != 0) { + this._kb = var1._kb; + } + + if (var1.mouseOverNineSliceSprites != null) { + this.mouseOverNineSliceSprites = var1.mouseOverNineSliceSprites; + } + + if (var1.disabledNineSliceSprites != null) { + this.disabledNineSliceSprites = var1.disabledNineSliceSprites; + } + + if (var1._H) { + this._H = true; + } + + if (var1._I != 256) { + this._I = var1._I; + } + + if (var1._qb >= 0) { + this._qb = var1._qb; + } + + if (var1.mouseOverTextColor >= 0) { + this.mouseOverTextColor = var1.mouseOverTextColor; + } + + if (var1._u != null) { + this._u = var1._u; + } + + if (var1.disabledSprite != null) { + this.disabledSprite = var1.disabledSprite; + } + + if (var1._W >= 0) { + this._W = var1._W; + } + + if (var1._ab >= 0) { + this._ab = var1._ab; + } + + if (var1.mouseHeldNineSliceSprites != null) { + this.mouseHeldNineSliceSprites = var1.mouseHeldNineSliceSprites; + } + + if (var1.nineSliceSprites != null) { + this.nineSliceSprites = var1.nineSliceSprites; + } + + if (var1.sprite != null) { + this.sprite = var1.sprite; + } + + if (var1.mouseOverSprite != null) { + this.mouseOverSprite = var1.mouseOverSprite; + } + + if (var1._Y != 0) { + this._Y = var1._Y; + } + + if (var1.mouseHeldSprite != null) { + this.mouseHeldSprite = var1.mouseHeldSprite; + } + + if (var1.textColor != 0) { + this.textColor = var1.textColor; + } + + if (var1.font != null) { + this.font = var1.font; + } + + if (var1.activeNineSliceSprites != null) { + this.activeNineSliceSprites = var1.activeNineSliceSprites; + } + + if (var1._V != Integer.MIN_VALUE) { + this._V = var1._V; + } + + if (var1._T != Integer.MIN_VALUE) { + this._T = var1._T; + } + + if (var1.textAlignment != Font.HorizontalAlignment.LEFT) { + this.textAlignment = var1.textAlignment; + } + + if (var1._t != Integer.MIN_VALUE) { + this._t = var1._t; + } + + if (var1._tb != 0) { + this._tb = var1._tb; + } + + if (var1.isDraggable) { + this.isDraggable = true; + } + + if (var1.verticalAlignment != Font.VerticalAlignment.TOP) { + this.verticalAlignment = var1.verticalAlignment; + } + + if (var1._J != Integer.MIN_VALUE) { + this._J = var1._J; + } + } + } + + public final void setBounds(final int x, final int y, final int width, final int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this._gb = 0; + this._cb = 0; + this._w = 0; + this._S = 0; + } + + public final int e474() { + return this.a353(Integer.MAX_VALUE); + } + + public final void rootProcessMouseEvents(final boolean mouseNotYetHandled) { + clickConsumed = !mouseNotYetHandled; + mouseOverConsumed = !mouseNotYetHandled; + this.processMouseEvents(0, 0, Drawing.width, Drawing.height); + } + + private void a360(boolean var2, boolean dragging, final int var4, final int var5, boolean selected, final int var8, boolean isMouseOver, final boolean var10, final int var11) { + this.x2 = this.x + var4; + this.y2 = this.y + var5; + final int var12 = Drawing.left; + final int var13 = Drawing.top; + final int var14 = Drawing.right; + final int var15 = Drawing.bottom; + Drawing.expandBoundsToInclude(this.x2, this.y2, this.x2 + this.width, this.height + this.y2); + var2 &= this.enabled; + + if (!this._H) { + selected = this.selected; + isMouseOver = this.isMouseOverTarget; + dragging = this.dragButton != MouseState.Button.NONE; + } + + Sprite[] var16 = this.nineSliceSprites; + Sprite var17 = this.sprite; + int color = this.textColor; + int var19 = 0; + if (!var2) { + if (this.disabledSprite != null) { + var17 = this.disabledSprite; + } + + if (this._W >= 0) { + color = this._W; + } + + if (this.disabledNineSliceSprites != null) { + var16 = this.disabledNineSliceSprites; + } + } + + int var20 = 0; + if (isMouseOver) { + if (this.mouseOverSprite != null) { + var17 = this.mouseOverSprite; + } + if (this.mouseOverNineSliceSprites != null) { + var16 = this.mouseOverNineSliceSprites; + } + if (this.mouseOverTextColor >= 0) { + color = this.mouseOverTextColor; + } + } + + if (dragging) { + if (this._qb >= 0) { + color = this._qb; + } + + if (this.mouseHeldNineSliceSprites != null) { + var16 = this.mouseHeldNineSliceSprites; + } + + if (this.mouseHeldSprite != null) { + var17 = this.mouseHeldSprite; + } + + if (this._t != Integer.MIN_VALUE) { + var19 = this._t; + } + + if (this._J != Integer.MIN_VALUE) { + var20 = this._J; + } + } + + if (selected) { + if (this._V != Integer.MIN_VALUE) { + var19 = this._V; + } + + if (this._T != Integer.MIN_VALUE) { + var20 = this._T; + } + + if (this.activeNineSliceSprites != null) { + var16 = this.activeNineSliceSprites; + } + + if (this._Z != null) { + var17 = this._Z; + } + + if (this._ab >= 0) { + color = this._ab; + } + } + + final int var21 = var19; + int var22 = this._tb + var20; + if (this._r) { + NineSliceSprite.draw(var16, var4, var5, var11, var8); + } else { + NineSliceSprite.draw(var16, this.x2, this.y2, this.width, this.height); + } + + if (var17 != null) { + int var23 = this.x2 + var21; + if (this.textAlignment == Font.HorizontalAlignment.CENTER) { + var23 += (this.width - var17.offsetX) / 2; + } + + int var24 = var22 + this.y2; + if (this.verticalAlignment == Font.VerticalAlignment.MIDDLE) { + var24 += (this.height - var17.offsetY) / 2; + } + + if (this.textAlignment == Font.HorizontalAlignment.RIGHT) { + var23 += this.width - var17.offsetX; + } + + if (this.verticalAlignment == Font.VerticalAlignment.BOTTOM) { + var24 += this.height - var17.offsetY; + } + + var17.draw(var23, var24); + } + + if (this.label != null && this.font != null) { + String var25 = this.label; + if (var10 && this._u != null) { + var25 = var25 + this._u; + } + + if (this.font.measureLineWidth(var25) <= -(2 * this._kb) + this.width && !var25.contains("
")) { + if (this.verticalAlignment == Font.VerticalAlignment.MIDDLE) { + var22 += (-this.font.descent + this.height - this.font.ascent) / 2; + } else if (this.verticalAlignment == Font.VerticalAlignment.BOTTOM) { + var22 += -this.font.ascent - this.font.descent + this.height; + } + + if (this.textAlignment == Font.HorizontalAlignment.LEFT) { + this.font.draw(var25, var21 + this.x2 + this._kb, this.font.ascent + var22 + this.y2, color, this._I); + } else if (this.textAlignment == Font.HorizontalAlignment.CENTER) { + this.font.drawCentered(var25, var21 + this.x2 + this._kb + (this.width - this._kb * 2) / 2, this.y2 + var22 + this.font.ascent, color, this._I); + } else if (this.textAlignment == Font.HorizontalAlignment.RIGHT) { + this.font.drawRightAligned(var25, this.width - (this._kb * 2) + var21 + this.x2 + this._kb, var22 + this.y2 + this.font.ascent, color, this._I); + } else { + this.font.drawParagraph(var25, this._kb + this.x2 + var21, var22 + this.y2, this.width - 2 * this._kb, this.height, color, this._I, this.textAlignment, this.verticalAlignment, this._Y); + } + } else { + this.font.drawParagraph(var25, var21 + this._kb + this.x2, this.y2 + var22, this.width - 2 * this._kb, this.height, color, this._I, this.textAlignment, this.verticalAlignment, this._Y); + } + } + + if (this.children != null) { + for (final Component var26 : this.children) { + var26.a360(var2, dragging, this.x2 + var19, var20 + this.y2, selected, this.height, isMouseOver, var10, this.width); + } + } + + Drawing.setBounds(var12, var13, var14, var15); + } + +} diff --git a/src/main/java/funorb/client/lobby/ContextMenu.java b/src/main/java/funorb/client/lobby/ContextMenu.java new file mode 100644 index 0000000..6d1614d --- /dev/null +++ b/src/main/java/funorb/client/lobby/ContextMenu.java @@ -0,0 +1,446 @@ +package funorb.client.lobby; + +import funorb.Strings; +import funorb.client.lobby.ChatMessage.Channel; +import funorb.client.lobby.ChatMessage.FilterLevel; +import funorb.shatteredplans.C2SPacket; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.JagexApplet; +import funorb.shatteredplans.client.ShatteredPlansClient; +import funorb.shatteredplans.game.ai.TutorialAI2; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +import static funorb.client.lobby.ContextMenu.ClickAction.*; + +public final class ContextMenu { + public static String recipientPlayerName; + public static boolean _fpv = true; + public static long recipientPlayerId; + public static int roomShowingPlayers; + public static String normalizedRecipientPlayerName; + public static ContextMenu openInstance; + private static @NotNull FilterLevel chatFilterLobby = FilterLevel.ALL; + private static @NotNull FilterLevel chatFilterRoom = FilterLevel.ALL; + private static @NotNull FilterLevel chatFilterPrivate = FilterLevel.NONE; + public final Component target; + public final int roomId; + public final PopupMenu view; + public final String playerName; + private final String playerDisplayName; + private int[] _i; + private @Nullable Channel selectedChannel; + private final long playerId; + + public ContextMenu(final Component target, final long playerId, final String playerName, final String playerDisplayName, final int roomId, final @Nullable Channel selectedChannel) { + this.target = target; + target.selected = true; + this.view = new PopupMenu(Component._hdt); + this._i = null; + this.playerId = playerId; + this.playerName = playerName; + this.playerDisplayName = playerDisplayName; + this.roomId = roomId; + this.selectedChannel = selectedChannel; + } + + private static void sendChannelMessage() { + ShatteredPlansClient.currentChatChannel = Channel.LOBBY; + ShatteredPlansClient.isChatboxSelected = true; + } + + private static void sendPrivateMessage(final long playerId, final String playerName) { + ShatteredPlansClient.currentChatChannel = Channel.PRIVATE; + recipientPlayerId = playerId; + recipientPlayerName = playerName; + normalizedRecipientPlayerName = Strings.normalize(playerName); + ShatteredPlansClient.isChatboxSelected = true; + } + + public static void setChatFilter(final @NotNull Channel channel, + final @NotNull FilterLevel value) { + if (channel == Channel.LOBBY && chatFilterLobby != value) { + _fpv = true; + chatFilterLobby = value; + C2SPacket.setChatFilters(getChatFilters()); + } + if (channel == Channel.ROOM && chatFilterRoom != value) { + _fpv = true; + chatFilterRoom = value; + C2SPacket.setChatFilters(getChatFilters()); + } + if (channel == Channel.PRIVATE && chatFilterPrivate != value) { + _fpv = true; + chatFilterPrivate = value; + C2SPacket.setChatFilters(getChatFilters()); + } + } + + private static void sendPrivateMessageQC(final String recipientName, final long var1) { + recipientPlayerName = recipientName; + ShatteredPlansClient.currentChatChannel = Channel.PRIVATE; + normalizedRecipientPlayerName = Strings.normalize(recipientName); + recipientPlayerId = var1; + r150bo(); + } + + public static void sendChannelMessageQC() { + ShatteredPlansClient.currentChatChannel = Channel.LOBBY; + r150bo(); + } + + private static void r150bo() { + a130bp(Component._ofb); + } + + public static boolean autoRespond(final long var0, final String var2, final int[] var4, @NotNull Channel channel) { + if (TutorialAI2.a051(var4, var2, channel, var0)) { + if (channel == Channel.ROOM) { + channel = Channel.LOBBY; + } + + ShatteredPlansClient.currentChatChannel = channel; + recipientPlayerName = var2; + normalizedRecipientPlayerName = Strings.normalize(var2); + recipientPlayerId = var0; + final vm_ var6 = a925bo(var4, Component._nld, Component._hlI, ReportAbuseDialog._Nb); + a130bp(var6); + return true; + } else { + return false; + } + } + + private static vm_ a925bo(final int[] var0, final Component var2, final Component var3, final Component var4) { + final int var5 = var0.length; + final String[] var6 = new String[var5]; + final char[] var7 = new char[var5]; + final vm_[] var8 = new vm_[var5]; + char var9 = '1'; + + try { + + for (int var10 = 0; var5 > var10; ++var10) { + final QuickChatResponse var11 = JagexApplet._dhc.get(var0[var10]); + var6[var10] = var11.joinStrings(); + var7[var10] = var9++; + var8[var10] = null; + } + } catch (final Exception var12) { + return null; + } + + return new vm_(var3, var4, var2, var8, var0, var6, var7); + } + + private static void a130bp(final vm_ var1) { + if (var1 != null) { + ShatteredPlansClient._dmrh = var1; + Component._uaf.children.clear(); + Component._uaf.addChild(ShatteredPlansClient._dmrh); + ShatteredPlansClient.isQuickChatOpen = true; + } + } + + public static String addFriend(final String playerName) { + if (!PlayerListEntry.isValidPlayerName(playerName)) { + return StringConstants.INVALID_NAME; + } else if (PlayerListEntry.serverStatus != PlayerListEntry.ServerStatus.LOADED) { + return StringConstants.UNABLE_TO_ADD_FRIEND; + } else if (JagexApplet.a623jp(playerName)) { + return StringConstants.CANNOT_ADD_YOURSELF; + } else if (ShatteredPlansClient.a988da(playerName)) { + return Strings.format(StringConstants.FRIEND_LIST_DUPE, playerName); + } else if (PlayerListEntry.friendCount >= 100 && JagexApplet.membershipLevel <= 0) { + return StringConstants.FRIEND_LIST_FULL; + } else if (PlayerListEntry.friendCount >= 200) { + return StringConstants.FRIEND_LIST_FULL; + } else if (PlayerListEntry.isIgnored(playerName)) { + return Strings.format(StringConstants.REMOVE_FROM_IGNORE_FIRST, playerName); + } else { + C2SPacket.friendIgnore(0, playerName); + return null; + } + } + + public static String addIgnore(final String var1) { + if (PlayerListEntry.isValidPlayerName(var1)) { + if (JagexApplet.a623jp(var1)) { + return StringConstants.CANNOT_ADD_YOURSELF; + } else if (PlayerListEntry.serverStatus != PlayerListEntry.ServerStatus.LOADED) { + return StringConstants.UNABLE_TO_ADD_IGNORE; + } else if (PlayerListEntry.isIgnored(var1)) { + return Strings.format(StringConstants.IGNORE_LIST_DUPE, var1); + } else if (PlayerListEntry.ignoreCount < 100) { + if (ShatteredPlansClient.a988da(var1)) { + return Strings.format(StringConstants.REMOVE_FRIEND_FIRST, var1); + } else { + C2SPacket.friendIgnore(2, var1); + return null; + } + } else { + return StringConstants.IGNORE_LIST_FULL; + } + } else { + return StringConstants.INVALID_NAME; + } + } + + public static void showChatMessage(final @NotNull Channel channel, final @NotNull String message, final int var2, final String var3, final String var4) { + showChatMessage(new ChatMessage(channel, var3, var2, var4, message)); + } + + private static void showPlayersInRoom(final int roomId) { + if (roomShowingPlayers != roomId) { + final ClientLobbyRoom prevRoomShowingPlayers = ClientLobbyRoom.roomsMap.get(roomShowingPlayers); + roomShowingPlayers = roomId; + if (prevRoomShowingPlayers != null) { + prevRoomShowingPlayers.joinedPlayerNames = null; + } + C2SPacket.showPlayersInGame(roomId); + } + } + + private static int getChatFilters() { + return chatFilterPrivate.encode() + (chatFilterRoom.encode() << 2) + (chatFilterLobby.encode() << 4); + } + + public static void setChatFilters(final int packed) { + chatFilterLobby = FilterLevel.decode(Math.min((packed >> 4) & 0b11, 2)); + chatFilterRoom = FilterLevel.decode(Math.min((packed >> 2) & 0b11, 2)); + chatFilterPrivate = FilterLevel.decode(Math.min(packed & 0b11, 2)); + } + + public static @NotNull FilterLevel getChatChannelFilter(final @NotNull Channel channel) { + return switch (channel) { + case LOBBY -> chatFilterLobby; + case ROOM -> chatFilterRoom; + case PRIVATE -> chatFilterPrivate; + default -> FilterLevel.ALL; + }; + } + + public static void showChatMessage(final ChatMessage message) { + for (int i = 0; i < 3; ++i) { + ShatteredPlansClient._imb[i] = 0; + } + + for (int i = 0; i < ShatteredPlansClient.chatMessageCount; ++i) { + if (ShatteredPlansClient.chatMessages[i].channel == message.channel) { + ShatteredPlansClient._imb[ShatteredPlansClient.chatMessages[i].a410().ordinal()]++; + } + } + ShatteredPlansClient._imb[message.a410().ordinal()]++; + + int var1 = 0; + for (int i = 0; i < ShatteredPlansClient.chatMessageCount; ++i) { + if (ShatteredPlansClient.chatMessages[i].channel == message.channel) { + final Channel var3 = ShatteredPlansClient.chatMessages[i].a410(); + if (ShatteredPlansClient._kpi < ShatteredPlansClient._imb[var3.ordinal()]) { + ShatteredPlansClient._imb[var3.ordinal()]--; + continue; + } + } + + ShatteredPlansClient.chatMessages[var1++] = ShatteredPlansClient.chatMessages[i]; + } + + ShatteredPlansClient.chatMessageCount = var1; + ShatteredPlansClient.chatMessages[ShatteredPlansClient.chatMessageCount++] = message; + } + + public void addPlayerItems(final boolean var1) { + if (this.playerName != null && this.playerId != ShatteredPlansClient.localPlayerId && ShatteredPlansClient.unratedLobbyRoom != null && ShatteredPlansClient.isCurrentRoomOwner()) { + final LobbyPlayer var3 = LobbyPlayer.getOnline(this.playerId); + final LobbyPlayer var4 = LobbyPlayer.getJoined(this.playerId); + final String var5 = this.a738(); + if (var4 != null) { + if (!ShatteredPlansClient.unratedLobbyRoom.hasStarted || ShatteredPlansClient.unratedLobbyRoom.finalElapsedTime >= 0) { + this.view.addItem(Strings.format(StringConstants.MU_GAMEOPT_KICK_X_FROM_THIS_GAME, var5), KICK_FROM_GAME); + } + } else if (var3 != null && ShatteredPlansClient.unratedLobbyRoom.notInProgress && ShatteredPlansClient.unratedLobbyRoom.joinedPlayerCount < ShatteredPlansClient.unratedLobbyRoom.maxPlayerCount) { + if (var3.inviteSent) { + this.view.addItem(Strings.format(StringConstants.MU_GAMEOPT_WITHDRAW_INVITE_TO_X, var5), KICK_FROM_GAME); + } else if (var1 && var3.joinRequestReceived) { + this.view.addItem(Strings.format(StringConstants.MU_GAMEOPT_ACCEPT_X_INTO_GAME, var5), INVITE_TO_GAME); + this.view.addItem(Strings.format(StringConstants.MU_GAMEOPT_REJECT_X_FROM_GAME, var5), KICK_FROM_GAME); + } else { + this.view.addItem(Strings.format(StringConstants.MU_GAMEOPT_INVITE_X_TO_GAME, var5), INVITE_TO_GAME); + } + } + } + } + + public boolean tick(final boolean mouseNotYetHandled) { + @MagicConstant(valuesFromClass = ClickAction.class) + final int which = this.view.getClickAction(mouseNotYetHandled); + if (which == PASS) { + return false; + } else { + switch (which) { + case INVITE_TO_GAME -> C2SPacket.inviteToGame(this.playerId); + case KICK_FROM_GAME -> C2SPacket.kickFromGame(this.playerId); + + case SUBMIT_JOIN_ROOM_REQUEST -> C2SPacket.requestToJoinRoom(this.roomId); + case WITHDRAW_JOIN_ROOM_REQUEST -> C2SPacket.requestToLeaveRoom(this.roomId); + case SPECTATE_GAME -> C2SPacket.spectateGame(this.roomId); + case SHOW_PLAYERS_IN_GAME -> showPlayersInRoom(this.roomId); + case HIDE_PLAYERS_IN_GAME -> showPlayersInRoom(0); + + case ADD_FRIEND -> this.maybeShowSocialActionError(addFriend(this.playerName)); + case REMOVE_FRIEND -> this.maybeShowSocialActionError(PlayerListEntry.removeFriend(this.playerName)); + case ADD_IGNORE -> this.maybeShowSocialActionError(addIgnore(this.playerName)); + case REMOVE_IGNORE -> this.maybeShowSocialActionError(PlayerListEntry.removeIgnore(this.playerName, this.playerDisplayName)); + + case CHAT_SHOW_ALL -> setChatFilter(Objects.requireNonNull(this.selectedChannel), FilterLevel.ALL); + case CHAT_SHOW_FRIENDS -> setChatFilter(Objects.requireNonNull(this.selectedChannel), FilterLevel.FRIENDS); + case CHAT_SHOW_NONE -> setChatFilter(Objects.requireNonNull(this.selectedChannel), FilterLevel.NONE); + + case SEND_PRIVATE_MESSAGE -> sendPrivateMessage(this.playerId, this.playerName); + case SEND_CHANNEL_MESSAGE -> sendChannelMessage(); + case SEND_PRIVATE_MESSAGE_QC -> sendPrivateMessageQC(this.playerName, this.playerId); + case SEND_CHANNEL_MESSAGE_QC -> sendChannelMessageQC(); + case AUTO_RESPOND -> autoRespond(this.playerId, this.playerName, this._i, Objects.requireNonNull(this.selectedChannel)); + case REPORT_ABUSE -> this.openReportAbuseDialog(); + } + return true; + } + } + + private void maybeShowSocialActionError(final String message) { + if (message != null) { + showChatMessage(Channel.PRIVATE, message, 0, this.playerName, null); + } + } + + private void openReportAbuseDialog() { + ReportAbuseDialog.openInstance = new ReportAbuseDialog(this.target.x2, this.target.y2, this.target.width, this.target.height, Component.TAB_ACTIVE, Component.CLOSE_BUTTON, Component.LABEL, Component.CHECKBOX, Component.UNSELECTED_LABEL, this.playerName, this.playerId); + } + + public void a124(final int[] var1, final @NotNull Channel var2) { + if (this.playerName != null && (this.playerId != ShatteredPlansClient.localPlayerId || var2 == Channel.PRIVATE) && PlayerListEntry.serverStatus == PlayerListEntry.ServerStatus.LOADED) { + final String var4 = this.a738(); + final PlayerListEntry var5 = PlayerListEntry.lookupFriend(this.playerName); + final boolean var6 = PlayerListEntry.isIgnored(this.playerName); + if (var5 == null && !var6) { + this.view.addItem(Strings.format(StringConstants.ADD_X_TO_FRIENDS, var4), ADD_FRIEND); + this.view.addItem(Strings.format(StringConstants.ADD_X_TO_IGNORE, var4), ADD_IGNORE); + if (var1 != null && var2 != Channel.PRIVATE && !JagexApplet.cannotChat) { + this._i = var1; + this.view.addItem(Strings.format(StringConstants.AUTO_RESPOND, var4), AUTO_RESPOND); + } + } + + if (var5 != null) { + if (!ShatteredPlansClient.isComposingChatMessageTo(this.playerName) && !JagexApplet.cannotChat) { + if (!JagexApplet.canOnlyQuickChat) { + this.view.addItem(Strings.format(StringConstants.SEND_PM_TO_X, var4), SEND_PRIVATE_MESSAGE); + } + + this.view.addItem(Strings.format(StringConstants.SEND_QC_TO_X, var4), SEND_PRIVATE_MESSAGE_QC); + if (var1 != null) { + this._i = var1; + this.view.addItem(Strings.format(StringConstants.AUTO_RESPOND, var4), AUTO_RESPOND); + } + } + + this.view.addItem(Strings.format(StringConstants.RM_X_FROM_FRIENDS, var4), REMOVE_FRIEND); + } + + if (var6) { + this.view.addItem(Strings.format(StringConstants.RM_X_FROM_IGNORE, var4), REMOVE_IGNORE); + } + } + } + + private String a738() { + return this.playerDisplayName == null ? this.playerName : this.playerDisplayName; + } + + public void b150() { + + if (this.playerName != null && ShatteredPlansClient.localPlayerId != this.playerId) { + final String var2 = this.a738(); + this.view.addItem(Strings.format(StringConstants.REPORT_X_FOR_ABUSE, var2), REPORT_ABUSE); + } + + } + + public void a430(final boolean var2) { + + this.view.b540(var2); + } + + public void a408(final ChatMessage message) { + if (!message._h) { + this.selectedChannel = message.channel; + if (message.channel == Channel.LOBBY) { + if (chatFilterLobby == FilterLevel.ALL) { + this.view.addItem(StringConstants.MU_CHAT_LOBBY_FRIENDS_ONLY, CHAT_SHOW_FRIENDS); + } + this.view.addItem(StringConstants.MU_CHAT_LOBBY_HIDE, CHAT_SHOW_NONE); + } else if (message.channel == Channel.ROOM) { + if (chatFilterRoom == FilterLevel.ALL) { + this.view.addItem(StringConstants.MU_CHAT_GAME_FRIENDS_ONLY, CHAT_SHOW_FRIENDS); + } + this.view.addItem(StringConstants.MU_CHAT_GAME_HIDE, CHAT_SHOW_NONE); + } else if (message.channel == Channel.PRIVATE) { + if (chatFilterPrivate == FilterLevel.ALL) { + this.view.addItem(StringConstants.MU_CHAT_PM_FRIENDS_ONLY, CHAT_SHOW_FRIENDS); + } + this.view.addItem(StringConstants.MU_CHAT_INVISIBLE_AND_SILENT_MODE, CHAT_SHOW_NONE); + } + } + } + + public void a487() { + if (ShatteredPlansClient.unratedLobbyRoom == null) { + final ClientLobbyRoom room = ClientLobbyRoom.lookup(this.roomId); + if (room != null) { + if (room.youAreInvited) { + this.view.addItem(Strings.format(StringConstants.ACCEPT_PLAYER_INVITATION, room.ownerName), SUBMIT_JOIN_ROOM_REQUEST); + this.view.addItem(Strings.format(StringConstants.INVITE_DECLINE_XS_GAME, room.ownerName), WITHDRAW_JOIN_ROOM_REQUEST); + } else { + if (room.youCanJoin) { + this.view.addItem(Strings.format(StringConstants.JOIN_XS_GAME, room.ownerName), SUBMIT_JOIN_ROOM_REQUEST); + } else if (!room.submittedJoinRequest && room.notInProgress && !room.hasStarted) { + this.view.addItem(Strings.format(StringConstants.JOIN_REQUEST_XS_GAME, room.ownerName), SUBMIT_JOIN_ROOM_REQUEST); + } + + if (room.submittedJoinRequest) { + this.view.addItem(Strings.format(StringConstants.JOIN_WITHDRAW_REQUEST_XS_GAME, room.ownerName), WITHDRAW_JOIN_ROOM_REQUEST); + } + } + } + } + } + + @SuppressWarnings("WeakerAccess") + public static final class ClickAction { + public static final int NONE = -1; + public static final int PASS = -2; + public static final int INVITE_TO_GAME = 0; + public static final int KICK_FROM_GAME = 1; + public static final int SUBMIT_JOIN_ROOM_REQUEST = 2; + public static final int WITHDRAW_JOIN_ROOM_REQUEST = 3; + public static final int ADD_FRIEND = 4; + public static final int REMOVE_FRIEND = 5; + public static final int ADD_IGNORE = 6; + public static final int REMOVE_IGNORE = 7; + public static final int SEND_PRIVATE_MESSAGE = 8; + public static final int SPECTATE_GAME = 10; + public static final int CHAT_SHOW_ALL = 11; + public static final int CHAT_SHOW_FRIENDS = 12; + public static final int CHAT_SHOW_NONE = 13; + public static final int SEND_CHANNEL_MESSAGE = 14; + public static final int SHOW_PLAYERS_IN_GAME = 15; + public static final int HIDE_PLAYERS_IN_GAME = 16; + public static final int REPORT_ABUSE = 17; + public static final int SEND_PRIVATE_MESSAGE_QC = 18; + public static final int AUTO_RESPOND = 19; + public static final int SEND_CHANNEL_MESSAGE_QC = 20; + } +} diff --git a/src/main/java/funorb/client/lobby/LobbyPlayer.java b/src/main/java/funorb/client/lobby/LobbyPlayer.java new file mode 100644 index 0000000..49faa52 --- /dev/null +++ b/src/main/java/funorb/client/lobby/LobbyPlayer.java @@ -0,0 +1,86 @@ +package funorb.client.lobby; + +import funorb.util.CollectionUtil; + +import java.util.List; +import java.util.Map; + +public final class LobbyPlayer extends Component> { + public static List online; + public static Map onlineMap; + public static List joinedPlayers; + public static Map joinedPlayersMap; + + public final long playerId; + public int rating; + public long joinedAt; + public int ratedGameCount; + public Component _xb; + public int unlockedOptionsBitmap; + public boolean joinRequestReceived; + public int statusTimer; + public Component _Ob; + public Component _Mb; + public int status; + public int crown; + public String playerDisplayName; + public boolean inviteSent; + public Component _Jb; + public String playerName; + public Component _Ab; + + public LobbyPlayer(final long playerId, final String playerName, final String playerDisplayName) { + super(null); + this.playerName = playerName; + this.playerDisplayName = playerDisplayName; + this.playerId = playerId; + } + + public static LobbyPlayer getOnline(final long playerId) { + return onlineMap.get(playerId); + } + + public static LobbyPlayer getJoined(final long playerId) { + return joinedPlayersMap.get(playerId); + } + + public static void addOnline(final LobbyPlayer player) { + online.remove(player); + CollectionUtil.insertSorted(online, player, LobbyPlayer::lessThan); + } + + @SuppressWarnings("InverseElseComparator") + private boolean lessThan(final LobbyPlayer other) { + if (this.joinRequestReceived != other.joinRequestReceived) { + return this.joinRequestReceived; + } else if (this.inviteSent != other.inviteSent) { + return this.inviteSent; + } else { + return this.joinedAt < other.joinedAt; + } + } + + public void setName(final String name, final String displayName) { + this.playerName = name; + this.playerDisplayName = displayName; + } + + public boolean isInMap() { + return onlineMap.containsKey(this.playerId) || joinedPlayersMap.containsKey(this.playerId); + } + + public static final class Status { + public static final int NONE = 0; + public static final int ENTERED_GAME = 1; + public static final int JOINED_YOUR_GAME = 2; + public static final int ENTERED_OTHER_GAME = 3; + public static final int LEFT_LOBBY = 4; + public static final int LOST_CON = 5; + public static final int CANNOT_JOIN_FULL = 6; + public static final int CANNOT_JOIN_IN_PROGRESS = 7; + public static final int DECLINED_INVITE = 8; + public static final int WITHDREW_REQUEST = 11; + public static final int KICKED = 12; + public static final int DROPPED_OUT = 13; + } +} diff --git a/src/main/java/funorb/client/lobby/PlayerList.java b/src/main/java/funorb/client/lobby/PlayerList.java new file mode 100644 index 0000000..5eebc91 --- /dev/null +++ b/src/main/java/funorb/client/lobby/PlayerList.java @@ -0,0 +1,49 @@ +package funorb.client.lobby; + +public final class PlayerList extends Component> { + public final Component entries; + public final ScrollPane scrollPane; + public final Component addButton; + public final Component removeButton; + + public PlayerList(final PlayerList other, final String addLabel, final String removeLabel) { + this(other, other.scrollPane.viewport, other.scrollPane.scrollBar, other.addButton, addLabel, removeLabel); + } + + public PlayerList(final Component attrsSrc, final Component viewportAttrsSrc, final ScrollBar scrollBar, final Component buttonAttrsSrc, final String addLabel, final String removeLabel) { + super(attrsSrc); + this.entries = new Component<>(null); + this.scrollPane = new ScrollPane<>(this.entries, viewportAttrsSrc, scrollBar); + this.addButton = new Component<>(buttonAttrsSrc); + this.removeButton = new Component<>(buttonAttrsSrc); + this.addButton.label = addLabel; + this.removeButton.label = removeLabel; + this.addChild(this.scrollPane); + this.addChild(this.addButton); + this.addChild(this.removeButton); + } + + @SuppressWarnings("SameParameterValue") + public void updateBounds(final int x, final int y, final int width, final int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.updateChildBounds(); + } + + public void updateChildBounds() { + final int buttonWidth = (this.width + 2) / 2; + final int paneHeight = this.height - 20; + //noinspection SuspiciousNameCombination + this.scrollPane.setBounds(0, 0, this.width, paneHeight - 2, LABEL_HEIGHT); + this.addButton.height = 20; + this.addButton.x = 0; + this.addButton.width = buttonWidth - 2; + this.addButton.y = paneHeight; + this.removeButton.width = this.width - buttonWidth; + this.removeButton.x = buttonWidth; + this.removeButton.y = paneHeight; + this.removeButton.height = 20; + } +} diff --git a/src/main/java/funorb/client/lobby/PlayerListEntry.java b/src/main/java/funorb/client/lobby/PlayerListEntry.java new file mode 100644 index 0000000..fe80bfa --- /dev/null +++ b/src/main/java/funorb/client/lobby/PlayerListEntry.java @@ -0,0 +1,256 @@ +package funorb.client.lobby; + +import funorb.Strings; +import funorb.commonui.form.validator.UsernameValidator; +import funorb.io.CipheredBuffer; +import funorb.shatteredplans.C2SPacket; +import funorb.shatteredplans.S2CPacket; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.JagexApplet; +import funorb.shatteredplans.client.ShatteredPlansClient; +import funorb.util.CollectionUtil; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.IntStream; + +public final class PlayerListEntry extends Component> { + @MagicConstant(valuesFromClass = ServerStatus.class) + public static int serverStatus = ServerStatus.UNINITIALIZED; + public static int ignoreCount; + private static List ignores; + private static Map ignoreMap; + public static int friendCount; + private static List friends; + private static Map friendMap; + + public String playerDisplayName; + public String playerName; + public Component serverNameLabel; + public Component displayNameChangedIcon; + private int index; + public String serverName; + public String previousDisplayName; + public Component playerNameLabel; + + private PlayerListEntry() { + super(null); + } + + public static String removeFriend(final String playerName) { + if (!isValidPlayerName(playerName)) { + return StringConstants.INVALID_NAME; + } + if (serverStatus != ServerStatus.LOADED) { + return StringConstants.UNABLE_TO_DELETE_FRIEND; + } + + final PlayerListEntry entry = lookupFriend(playerName); + if (entry == null) { + return Strings.format(StringConstants.FRIEND_NOT_FOUND, playerName); + } + + final int entryIndex = friends.indexOf(entry); + friends.remove(entryIndex); + friends.stream().skip(entryIndex).forEach(entry1 -> entry1.index--); + friendMap.remove(Strings.normalize(playerName)); + friendCount--; + C2SPacket.friendIgnore(1, playerName); + return null; + } + + static boolean isValidPlayerName(final CharSequence playerName) { + return UsernameValidator.isValidUsername(playerName, true) + && IntStream.range(0, playerName.length()).allMatch(i -> Strings.isNormalizable(playerName.charAt(i))); + } + + public static String removeIgnore(final String playerName, final String playerDisplayName) { + if (!isValidPlayerName(playerName)) { + return StringConstants.INVALID_NAME; + } else if (serverStatus == ServerStatus.LOADED) { + final PlayerListEntry var4 = lookupIgnore(playerDisplayName); + if (var4 == null) { + return Strings.format(StringConstants.IGNORE_NOT_FOUND, playerDisplayName); + } else { + ignores.remove(var4); + ignoreMap.remove(Strings.normalizeIfPossible(playerDisplayName)); + --ignoreCount; + + C2SPacket.friendIgnore(3, playerName); + return null; + } + } else { + return StringConstants.UNABLE_TO_DELETE_IGNORE; + } + } + + private boolean lessThan(final PlayerListEntry other) { + int delta = other.index - this.index; + + if (Objects.equals(other.serverName, ShatteredPlansClient.currentServerName)) { + delta -= 200; + } else if (other.serverName == null) { + delta += 200; + } + if (Objects.equals(this.serverName, ShatteredPlansClient.currentServerName)) { + delta += 200; + } else if (this.serverName == null) { + delta -= 200; + } + + return delta > 0; + } + + public static boolean isIgnored(final String displayName) { + return lookupIgnore(displayName) != null; + } + + private static PlayerListEntry lookupIgnore(final String displayName) { + return ignoreMap == null ? null : ignoreMap.get(Strings.normalizeIfPossible(displayName)); + } + + public static PlayerListEntry lookupFriend(final String displayName) { + return (friendMap == null || displayName == null || displayName.isEmpty()) + ? null + : friendMap.get(Strings.normalize(displayName)); + } + + public static void initialize(final @NotNull Component friendList, final @NotNull Component ignoreList) { + if (friendList.children == null) { + friendList.children = new ArrayList<>(); + } + if (ignoreList.children == null) { + ignoreList.children = new ArrayList<>(); + } + if (friendMap == null) { + friendMap = new HashMap<>(); + } + if (ignoreMap == null) { + ignoreMap = new HashMap<>(); + } + + friends = friendList.children; + ignores = ignoreList.children; + reset(); + } + + public static void reset() { + ShatteredPlansClient.currentServerName = null; + friendCount = 0; + ignoreCount = 0; + friends.clear(); + ignores.clear(); + friendMap.clear(); + ignoreMap.clear(); + serverStatus = ServerStatus.UNINITIALIZED; + } + + public static void handleSocialPacket(@SuppressWarnings("SameParameterValue") final CipheredBuffer packet) { + final int type = packet.readUByte(); + if (type == S2CPacket.SocialAction.IGNORE) { + handleIgnorePacket(packet); + } else if (type == S2CPacket.SocialAction.FRIEND) { + handleFriendPacket(packet); + } else if (type == S2CPacket.SocialAction.LOADED) { + if (serverStatus == ServerStatus.LOADING) { + serverStatus = ServerStatus.LOADED; + } + } else if (type == S2CPacket.SocialAction.LOADING) { + if (serverStatus == ServerStatus.LOADED) { + serverStatus = ServerStatus.LOADING; + } + } else if (type == S2CPacket.SocialAction.INITIALIZE) { + serverStatus = ServerStatus.LOADING; + ShatteredPlansClient.currentServerName = packet.readNullTerminatedString().intern(); + ContextMenu.setChatFilters(packet.readUByte()); + } else { + JagexApplet.clientError(null, "F1: " + JagexApplet.a738w()); + JagexApplet.shutdownServerConnection(); + } + } + + private static void handleIgnorePacket(final CipheredBuffer packet) { + if (ignoreMap == null) { + ignoreMap = new HashMap<>(); + ignoreCount = 0; + } + + final boolean hasNonDisplayName = packet.readUByte() == 1; + final String displayName = packet.readNullTerminatedString(); + final String playerName; + if (hasNonDisplayName) { + playerName = packet.readNullTerminatedString(); + } else { + playerName = displayName; + } + + PlayerListEntry entry = lookupIgnore(displayName); + final String previousName = packet.readNullTerminatedString(); + final String normalizedDisplayName = Strings.normalizeIfPossible(displayName); + + if (entry == null) { + entry = lookupIgnore(previousName); + if (entry != null) { + ignoreMap.put(normalizedDisplayName, entry); + } + } + + if (entry == null) { + entry = new PlayerListEntry(); + ignoreMap.put(normalizedDisplayName, entry); + entry.index = ignoreCount++; + ignores.add(entry); + } + + entry.playerName = playerName; + entry.playerDisplayName = displayName; + entry.previousDisplayName = previousName; + } + + private static void handleFriendPacket(final CipheredBuffer packet) { + if (friendMap == null) { + friendMap = new HashMap<>(); + friendCount = 0; + } + + String serverName = packet.readNullableNullTerminatedString(); + if (serverName != null) { + serverName = serverName.intern(); + } + + final String displayName = packet.readNullTerminatedString(); + final String previousDisplayName = packet.readNullTerminatedString(); + PlayerListEntry entry = lookupFriend(displayName); + if (entry == null) { + entry = lookupFriend(previousDisplayName); + if (entry != null) { + friendMap.put(Strings.normalize(displayName), entry); + } + } + + if (entry == null) { + entry = new PlayerListEntry(); + friendMap.put(Strings.normalize(displayName), entry); + entry.index = friendCount++; + } + + entry.playerDisplayName = displayName; + entry.serverName = serverName; + entry.previousDisplayName = previousDisplayName; + + friends.remove(entry); + CollectionUtil.insertSorted(friends, entry, PlayerListEntry::lessThan); + } + + @SuppressWarnings("WeakerAccess") + public static final class ServerStatus { + public static final int UNINITIALIZED = 0; + public static final int LOADING = 1; + public static final int LOADED = 2; + } +} diff --git a/src/main/java/funorb/client/lobby/PopupMenu.java b/src/main/java/funorb/client/lobby/PopupMenu.java new file mode 100644 index 0000000..5aa3386 --- /dev/null +++ b/src/main/java/funorb/client/lobby/PopupMenu.java @@ -0,0 +1,143 @@ +package funorb.client.lobby; + +import funorb.awt.KeyState; +import funorb.awt.MouseState; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.graphics.Sprite; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.JagexApplet; +import org.intellij.lang.annotations.MagicConstant; + +public final class PopupMenu extends Component> { + private final int _yb; + private final Component _Nb; + private final Sprite[] _Lb; + private final Component _Mb; + private final int _Eb; + private final int _Kb; + private final int _zb; + private final int _Jb; + private final ActionButton[] items; + @MagicConstant(valuesFromClass = ContextMenu.ClickAction.class) + private final int[] actions; + private int _Bb; + private int clickTargetCount; + + public PopupMenu(final PopupMenu attrsSrc) { + this(attrsSrc, attrsSrc._Lb, attrsSrc._Nb, attrsSrc._Mb, attrsSrc._Kb, attrsSrc._Eb, attrsSrc._Jb, attrsSrc._yb, attrsSrc._zb); + } + + public PopupMenu(final Component attrsSrc, final Sprite[] var2, final Component var3, final Component var4, final int var5, final int var6, final int var7, final int var8, final int var9) { + super(attrsSrc); + this.actions = new int[256]; + this.items = new ActionButton[256]; + this._Bb = -2; + this._Kb = var5; + this._Lb = var2; + this._zb = var9; + this._Mb = var4; + this._Jb = var7; + this._Nb = var3; + this._Eb = var6; + this._yb = var8; + } + + public static int positionPopupX(final int targetX, final int targetWidth, final int popupWidth) { + if (targetX + popupWidth <= Drawing.width) { + return targetX; + } else if (targetX + targetWidth - popupWidth >= 0) { + return targetX + targetWidth - popupWidth; + } else { + return Drawing.width - popupWidth; + } + } + + public static int positionPopupY(final int targetY, final int targetHeight, final int popupHeight) { + if (popupHeight + targetHeight + targetY <= Drawing.height) { + return targetY + targetHeight; + } else if (targetY - popupHeight >= 0) { + return targetY - popupHeight; + } else { + return Drawing.height - popupHeight; + } + } + + public boolean f427() { + if (this._Bb == -2) { + if (JagexApplet.lastTypedKeyCode == KeyState.Code.ESCAPE) { + this._Bb = -1; + } + return true; + } else { + return false; + } + } + + public void addItem(final Sprite sprite, final String tooltip, @MagicConstant(valuesFromClass = ContextMenu.ClickAction.class) final int action) { + this.items[this.clickTargetCount] = new ActionButton(null, this._Mb, sprite, tooltip); + this.items[this.clickTargetCount].mouseOverNineSliceSprites = this._Lb; + this.items[this.clickTargetCount]._r = true; + this.items[this.clickTargetCount].verticalAlignment = Font.VerticalAlignment.MIDDLE; + this.addChild(this.items[this.clickTargetCount]); + this.actions[this.clickTargetCount] = action; + ++this.clickTargetCount; + } + + public void addItem(final String tooltip, @MagicConstant(valuesFromClass = ContextMenu.ClickAction.class) final int action) { + this.addItem(null, tooltip, action); + } + + public void positionRelativeToTarget(final int targetX, final int targetY) { + this.positionRelativeToTarget(targetX, targetY, 0, 0); + } + + public void positionRelativeToTarget(final int targetX, final int targetY, final int targetWidth, final int targetHeight) { + if (this.clickTargetCount == 0) { + this.items[this.clickTargetCount] = new ActionButton(null, this._Nb, null, StringConstants.NO_OPTIONS_AVAILABLE); + this.items[this.clickTargetCount].verticalAlignment = Font.VerticalAlignment.MIDDLE; + this.addChild(this.items[this.clickTargetCount]); + this.actions[this.clickTargetCount] = -1; + ++this.clickTargetCount; + } + + int width = 0; + for (int i = 0; i < this.clickTargetCount; ++i) { + final int var8 = this.items[i].a776(this._Jb, this._Eb); + if (width < var8) { + width = var8; + } + } + + width += this._Kb * 2; + final int height = this._yb + this._yb + this.clickTargetCount * this._zb; + final int x = positionPopupX(targetX, targetWidth, width); + final int y = positionPopupY(targetY, targetHeight, height); + this.setBounds(x, y, width, height); + + for (int i = 0; i < this.clickTargetCount; ++i) { + this.items[i].a370(this._zb, this._yb + i * this._zb, this._Eb, this._Jb, width - (2 * this._Kb), this._Kb); + } + } + + @MagicConstant(valuesFromClass = ContextMenu.ClickAction.class) + public int getClickAction(final boolean mouseNotYetHandled) { + this.rootProcessMouseEvents(mouseNotYetHandled); + if (mouseNotYetHandled) { + for (int i = 0; i < this.clickTargetCount; ++i) { + if (this.items[i].clickButton != MouseState.Button.NONE) { + //noinspection MagicConstant + return this.actions[i]; + } + } + + if (JagexApplet.mouseButtonJustClicked == MouseState.Button.NONE) { + return this._Bb; + } else { + return ContextMenu.ClickAction.NONE; + } + } else { + return ContextMenu.ClickAction.PASS; + } + } +} diff --git a/src/main/java/funorb/client/lobby/QuickChatCategories.java b/src/main/java/funorb/client/lobby/QuickChatCategories.java new file mode 100644 index 0000000..d215d02 --- /dev/null +++ b/src/main/java/funorb/client/lobby/QuickChatCategories.java @@ -0,0 +1,36 @@ +package funorb.client.lobby; + +import funorb.cache.ResourceLoader; +import funorb.data.LRUCache; +import funorb.io.Buffer; + +public final class QuickChatCategories { + private final ResourceLoader loader; + private final LRUCache _b = new LRUCache<>(); + + public QuickChatCategories(final ResourceLoader loader) { + this.loader = loader; + if (this.loader != null) { + this.loader.itemCount(0); + } + } + + public QuickChatCategory get(final int id) { + final QuickChatCategory loadedCategory = this._b.get(id); + if (loadedCategory != null) { + return loadedCategory; + } + + final byte[] data = this.loader.getResource(0, id & 0x7fff); + final QuickChatCategory category = new QuickChatCategory(); + if (data != null) { + category.load(new Buffer(data)); + } + if (id >= 0x8000) { + category.markHigh(); + } + + this._b.put(id, category); + return category; + } +} diff --git a/src/main/java/funorb/client/lobby/QuickChatCategory.java b/src/main/java/funorb/client/lobby/QuickChatCategory.java new file mode 100644 index 0000000..0d5b579 --- /dev/null +++ b/src/main/java/funorb/client/lobby/QuickChatCategory.java @@ -0,0 +1,63 @@ +package funorb.client.lobby; + +import funorb.Strings; +import funorb.io.Buffer; + +import java.util.Arrays; + +public final class QuickChatCategory { + public boolean _y = false; + public String name; + public char[] _s; + public char[] _p; + public int[] _x; + public int[] _r; + + public void markHigh() { + if (this._x != null) { + Arrays.setAll(this._x, i -> this._x[i] | 0x8000); + } + if (this._r != null) { + Arrays.setAll(this._r, i -> this._r[i] | 0x8000); + } + } + + public void load(final Buffer buffer) { + while (true) { + final int type = buffer.readUByte(); + if (type == 0) { + return; + } + + this.loadEntry(buffer, type); + } + } + + private void loadEntry(final Buffer buffer, final int type) { + if (type == 1) { + this.name = buffer.readNullTerminatedString(); + } else if (type == 2) { + final int len = buffer.readUByte(); + this._p = new char[len]; + this._r = new int[len]; + + for (int i = 0; i < len; ++i) { + this._r[i] = buffer.readUShort(); + final byte var6 = buffer.readByte(); + this._p[i] = var6 == 0 ? 0 : Strings.decode1252Char(var6); + } + } else if (type == 3) { + final int var4 = buffer.readUByte(); + this._s = new char[var4]; + this._x = new int[var4]; + + for (int i = 0; i < var4; ++i) { + this._x[i] = buffer.readUShort(); + final byte var6 = buffer.readByte(); + this._s[i] = var6 == 0 ? 0 : Strings.decode1252Char(var6); + } + } else if (type == 4) { + this._y = true; + } + } +} diff --git a/src/main/java/funorb/client/lobby/QuickChatHelpPanel.java b/src/main/java/funorb/client/lobby/QuickChatHelpPanel.java new file mode 100644 index 0000000..47480c4 --- /dev/null +++ b/src/main/java/funorb/client/lobby/QuickChatHelpPanel.java @@ -0,0 +1,63 @@ +package funorb.client.lobby; + +import funorb.awt.MouseState; +import funorb.graphics.Font; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.JagexApplet; +import funorb.shatteredplans.client.ShatteredPlansClient; + +public final class QuickChatHelpPanel extends Component> { + public static QuickChatHelpPanel openInstance; + private final Component closeButton; + + public QuickChatHelpPanel(final Component var2, final Component var3, final Component var4) { + final Component> var7 = new Component<>(var2, StringConstants.QUICK_CHAT_HELP.toUpperCase()); + var7.textAlignment = Font.HorizontalAlignment.CENTER; + this.closeButton = new Component<>(var3); + final Component> var8 = new Component<>(var4); + final Component> var9 = new Component<>(var4, StringConstants.QUICK_CHAT_HELP_TITLE); + var9.textAlignment = Font.HorizontalAlignment.CENTER; + int var10 = 50; + int var11 = 0; + + for (int var12 = 0; var12 < StringConstants.QUICK_CHAT_SHORTCUT_HELP.length; ++var12) { + final Component var13 = new Component<>(var4, StringConstants.QUICK_CHAT_SHORTCUT_KEYS[var12]); + final Component var14 = new Component<>(var4, StringConstants.QUICK_CHAT_SHORTCUT_HELP[var12]); + final int var15 = var4.font.measureLineWidth(StringConstants.QUICK_CHAT_SHORTCUT_HELP[var12]); + var13.setBounds(20, var10, 65, 15); + if (var15 > var11) { + var11 = var15; + } + + var14.setBounds(90, var10, ShatteredPlansClient.SCREEN_WIDTH, 15); + var8.addChild(var13); + var8.addChild(var14); + var10 += 30; + } + + var10 += 15; + var7.setBounds(0, 0, 20 + var11 + 90, 24); + this.setBounds(100, 100, var7.width, var10 + var7.height); + this.closeButton.setBounds(var7.width - 20, 5, 15, 15); + var8.setBounds(0, var7.height, this.width, -var7.height + this.height); + var9.setBounds(0, 20, this.width, 15); + var8.nineSliceSprites = Component.createGradientOutlineSprites(var8.height, 11579568, 8421504, 2105376); + var7.addChild(this.closeButton); + var8.addChild(var9); + this.addChild(var7); + this.addChild(var8); + this.x = 320 - (this.width >> 1); + } + + public static void tick() { + if (openInstance != null && openInstance.isCloseRequested()) { + openInstance = null; + } + } + + private boolean isCloseRequested() { + this.rootProcessMouseEvents(true); + return (JagexApplet.mouseButtonJustClicked != MouseState.Button.NONE && this.clickButton == MouseState.Button.NONE) + || this.closeButton.clickButton != MouseState.Button.NONE; + } +} diff --git a/src/main/java/funorb/client/lobby/QuickChatResponse.java b/src/main/java/funorb/client/lobby/QuickChatResponse.java new file mode 100644 index 0000000..878a63e --- /dev/null +++ b/src/main/java/funorb/client/lobby/QuickChatResponse.java @@ -0,0 +1,59 @@ +package funorb.client.lobby; + +import funorb.io.Buffer; + +import java.util.Arrays; +import java.util.stream.Collectors; + +public final class QuickChatResponse { + private static final int[] SHORTS_TO_SKIP = {1, 0, 0, 0, 1, 0, 2, 1, 1, 1, 0, 2, 0, 0, 1, 0}; + + public int[] ids; + private String[] strings; + + public void load(final Buffer buffer) { + while (true) { + final int type = buffer.readUByte(); + if (type == 0) { + return; + } + + this.loadEntry(buffer, type); + } + } + + private void loadEntry(final Buffer buffer, final int type) { + if (type == 1) { + this.strings = buffer.readNullTerminatedString().split("<"); + } else if (type == 2) { + final int len = buffer.readUByte(); + this.ids = new int[len]; + for (int i = 0; i < len; ++i) { + this.ids[i] = buffer.readUShort(); + } + } else if (type == 3) { + final int len = buffer.readUByte(); + for (int i = 0; i < len; ++i) { + final int shortsToSkip = SHORTS_TO_SKIP[buffer.readUShort()]; + for (int j = 0; j < shortsToSkip; ++j) { + buffer.readUShort(); + } + } + } + } + + public void markHigh() { + if (this.ids != null) { + Arrays.setAll(this.ids, i -> this.ids[i] | 0x8000); + } + } + + public String joinStrings() { + if (this.strings == null) { + return ""; + } else { + return Arrays.stream(this.strings, 1, this.strings.length) + .collect(Collectors.joining("...", this.strings[0], "")); + } + } +} diff --git a/src/main/java/funorb/client/lobby/QuickChatResponses.java b/src/main/java/funorb/client/lobby/QuickChatResponses.java new file mode 100644 index 0000000..585cd6c --- /dev/null +++ b/src/main/java/funorb/client/lobby/QuickChatResponses.java @@ -0,0 +1,36 @@ +package funorb.client.lobby; + +import funorb.cache.ResourceLoader; +import funorb.data.LRUCache; +import funorb.io.Buffer; + +public final class QuickChatResponses { + private final ResourceLoader loader; + private final LRUCache _f = new LRUCache<>(); + + public QuickChatResponses(final ResourceLoader loader) { + this.loader = loader; + if (this.loader != null) { + this.loader.itemCount(1); + } + } + + public QuickChatResponse get(final int id) { + final QuickChatResponse loadedResponse = this._f.get(id); + if (loadedResponse != null) { + return loadedResponse; + } + + final byte[] data = this.loader.getResource(1, id & 0x7fff); + final QuickChatResponse response = new QuickChatResponse(); + if (data != null) { + response.load(new Buffer(data)); + } + if (id >= 0x8000) { + response.markHigh(); + } + + this._f.put(id, response); + return response; + } +} diff --git a/src/main/java/funorb/client/lobby/ReportAbuseDialog.java b/src/main/java/funorb/client/lobby/ReportAbuseDialog.java new file mode 100644 index 0000000..9a0c17b --- /dev/null +++ b/src/main/java/funorb/client/lobby/ReportAbuseDialog.java @@ -0,0 +1,273 @@ +package funorb.client.lobby; + +import funorb.awt.KeyState; +import funorb.awt.MouseState; +import funorb.graphics.Font; +import funorb.shatteredplans.C2SPacket; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.JagexApplet; +import funorb.shatteredplans.client.ShatteredPlansClient; + +public final class ReportAbuseDialog extends Component> { + public static Component _Nb; + public static String _Kb = "ESC - cancel private message"; + public static ReportAbuseDialog openInstance; + public static String[] RULE_STRINGS; + private final long _Gb; + private final Component _Ob; + private Component _Bb; + private Component[] _Hb; + private int _yb = -2; + private Checkbox _zb; + private StringBuilder _xb; + + public ReportAbuseDialog(final int var1, final int var2, final int var3, final int var4, final Component var7, final Component var8, final Component var9, final Checkbox var10, final Component var11, final String var12, final long var13) { + super(null); + this._Gb = var13; + final Component> _Jb = new Component<>(var7, StringConstants.RA_TITLE.toUpperCase()); + _Jb.textAlignment = Font.HorizontalAlignment.CENTER; + this.addChild(_Jb); + this._Ob = new Component<>(var8); + _Jb.addChild(this._Ob); + final Component> _Cb = new Component<>(null); + this.addChild(_Cb); + int var16; + int var17; + int var18; + int var19; + int var20; + int var31; + final Component _Ab; + if (var12 == null) { + _Ab = new Component<>(var9, StringConstants.RA_INTRO_NO_NAME); + _Ab.textAlignment = Font.HorizontalAlignment.CENTER; + _Ab.textColor = 11184810; + _Cb.addChild(_Ab); + final short var27 = 226; + final byte var30 = 10; + var17 = _Ab.font.breakLines(_Ab.label, var27); + _Ab.setBounds(13, var30, var27, Component.LABEL_HEIGHT * var17); + var16 = var30 + Component.LABEL_HEIGHT * var17; + _Cb.setBounds(0, 24, 252, var16 + 10); + _Cb.nineSliceSprites = createGradientOutlineSprites(_Cb.height, 11579568, 8421504, 2105376); + var18 = 252; + var19 = 34 + var16; + var20 = PopupMenu.positionPopupX(var1, var3, var18); + var31 = PopupMenu.positionPopupY(var2, var4, var19); + this.setBounds(var20, var31, var18, var19); + } else { + _Ab = new Component<>(var9, StringConstants.RA_INTRO); + _Ab.textAlignment = Font.HorizontalAlignment.CENTER; + _Ab.textColor = 11184810; + _Cb.addChild(_Ab); + final Component _Fb = new Component<>(var9, StringConstants.RA_EXPLANATION); + _Fb.textAlignment = Font.HorizontalAlignment.CENTER; + _Fb.textColor = 11184810; + _Cb.addChild(_Fb); + this._Bb = new Component<>(var9); + this._Bb.textColor = 16764006; + _Cb.addChild(this._Bb); + this._Bb._u = "|"; + if (JagexApplet.modLevel >= 5 || JagexApplet.adminLevel >= 2) { + this._zb = new Checkbox(var10, JagexApplet.modLevel < 7 && JagexApplet.adminLevel < 2 ? StringConstants.RA_SUGGEST_MUTE : StringConstants.RA_MUTE_THIS_PLAYER); + _Cb.addChild(this._zb); + } + + final Component> qr1 = new Component<>(null); + final Component> qr2 = new Component<>(null); + final Component> qr3 = new Component<>(null); + _Cb.addChild(qr1); + _Cb.addChild(qr2); + _Cb.addChild(qr3); + this._Hb = new Component[RULE_STRINGS.length]; + + for (var16 = 0; var16 < RULE_STRINGS.length; ++var16) { + if (RULE_STRINGS[var16] != null) { + this._Hb[var16] = new Component<>(var11, RULE_STRINGS[var16]); + this._Hb[var16].textAlignment = Font.HorizontalAlignment.LEFT; + this._Hb[var16].enabled = true; + _Cb.addChild(this._Hb[var16]); + } + } + + this._xb = new StringBuilder(12); + this._xb.append(var12); + + var16 = 0; + var17 = var7.font.measureLineWidth(StringConstants.RULE_PILLAR_0); + if (var17 > var16) { + var16 = var17; + } + + var17 = var7.font.measureLineWidth(StringConstants.RULE_PILLAR_1); + if (var17 > var16) { + var16 = var17; + } + + var17 = var7.font.measureLineWidth(StringConstants.RULE_PILLAR_2); + if (var17 > var16) { + var16 = var17; + } + + for (var17 = 0; var17 < RULE_STRINGS.length; ++var17) { + if (this._Hb[var17] != null) { + var18 = this._Hb[var17].e474(); + if (var16 < var18) { + var16 = var18; + } + } + } + + if (var16 > 140) { + var16 = 140; + } + + var17 = 0; + this.a315(var7, qr1, StringConstants.RULE_PILLAR_0, var16); + var18 = this.a082(qr1, this._Hb[6], 32, var16); + var18 = this.a082(qr1, this._Hb[9], var18, var16); + var18 = this.a082(qr1, this._Hb[5], var18, var16); + var18 = this.a082(qr1, this._Hb[7], var18, var16); + var18 = this.a082(qr1, this._Hb[15], var18, var16); + var18 = this.a082(qr1, this._Hb[4], var18, var16); + if (var17 < var18) { + var17 = var18; + } + + this.a315(var7, qr2, StringConstants.RULE_PILLAR_1, var16); + var18 = this.a082(qr2, this._Hb[16], 32, var16); + var18 = this.a082(qr2, this._Hb[17], var18, var16); + var18 = this.a082(qr2, this._Hb[18], var18, var16); + var18 = this.a082(qr2, this._Hb[19], var18, var16); + var18 = this.a082(qr2, this._Hb[20], var18, var16); + if (var18 > var17) { + var17 = var18; + } + + this.a315(var7, qr3, StringConstants.RULE_PILLAR_2, var16); + var18 = this.a082(qr3, this._Hb[13], 32, var16); + var18 = this.a082(qr3, this._Hb[21], var18, var16); + var18 = this.a082(qr3, this._Hb[11], var18, var16); + if (var18 > var17) { + var17 = var18; + } + + var19 = 3 * var16 + 26; + var20 = _Jb.e474(); + if (var20 > var19) { + var19 = var20; + } + + if (this._zb != null) { + var20 = this._zb.c080(); + if (var19 < var20) { + var19 = var20; + } + } + + _Jb.setBounds(0, 0, var19 + 26, 24); + this._Ob.setBounds(_Jb.width - 20, 5, 15, 15); + final byte var21 = 10; + _Ab.setBounds(13, var21, var19, Component.LABEL_HEIGHT * 2); + var31 = var21 + Component.LABEL_HEIGHT * 2; + _Fb.setBounds(13, var31, var19, Component.LABEL_HEIGHT * 2); + var31 += Component.LABEL_HEIGHT * 2 + 10; + this._Bb.setBounds(0, var31, 0, Component.LABEL_HEIGHT); + var31 += Component.LABEL_HEIGHT + 10; + if (this._zb != null) { + var20 = this._zb.c080(); + this._zb.a669(var20, 13 + (var19 - var20) / 2, var31); + var31 += Component.LABEL_HEIGHT + 10; + } + + qr1.setBounds(13, var31, var16, var17); + qr2.setBounds(13 + var16 + 13, var31, var16, var17); + qr3.setBounds(39 + var16 * 2, var31, var16, var17); + _Cb.setBounds(0, 24, 13 + var19 + 13, var17 + var31 + 10); + _Cb.nineSliceSprites = createGradientOutlineSprites(_Cb.height, 11579568, 8421504, 2105376); + final int var23 = 13 + 13 + var19; + final int var24 = var17 + 24 + var31 + 10; + final int var25 = PopupMenu.positionPopupX(var1, var3, var23); + final int var26 = PopupMenu.positionPopupY(var2, var4, var24); + this.setBounds(var25, var26, var23, var24); + } + + } + + public static void tick(final boolean mouseNotYetHandled) { + final int var3; + if (openInstance != null) { + var3 = openInstance.getAction(mouseNotYetHandled); + if (var3 != -2) { + if (var3 != -1) { + final boolean var4 = openInstance.i154(); + C2SPacket.reportAbuse(openInstance._Gb, var4, openInstance.g983(), var3); + } + + openInstance = null; + ShatteredPlansClient.dismissContextMenu(); + } + } + } + + private void a315(final Component var1, final Component> var2, final String var3, final int var4) { + var2.addChild(new Component<>(var1, var4, 24, var3)); + } + + private int a082(final Component> var2, final Component var3, int var4, final int var5) { + var4 += 8; + final int var6 = var3.font.measureParagraphHeight(var3.label, var5 - 2 * var3._kb, var3._Y); + var3.setBounds(0, var4, var5, var6); + var4 += var6; + var2.addChild(var3); + return var4; + } + + public boolean h154() { + if (this._yb == -2) { + if (JagexApplet.lastTypedKeyCode == KeyState.Code.ESCAPE) { + this._yb = -1; + } + + return true; + } else { + return false; + } + } + + private String g983() { + return this._xb.toString(); + } + + private int getAction(final boolean var1) { + this.rootProcessMouseEvents(var1); + if (this._Bb != null) { + this._Bb.label = this._xb.toString(); + this._Bb.x = (this.width - this._Bb.font.measureLineWidth(this._Bb.label)) / 2; + if (this._zb != null && this._zb.clickButton != MouseState.Button.NONE) { + this._zb.selected = !this._zb.selected; + } + + this._Bb.width = this.width - this._Bb.x; + + for (int var3 = 0; var3 < RULE_STRINGS.length; ++var3) { + if (this._Hb[var3] != null) { + this._Hb[var3].enabled = this._xb.length() > 0; + if (this._Hb[var3].enabled && this._Hb[var3].clickButton != MouseState.Button.NONE) { + return var3; + } + } + } + } + + if (this._Ob.clickButton == MouseState.Button.NONE) { + return var1 && JagexApplet.mouseButtonJustClicked != MouseState.Button.NONE && this.clickButton == MouseState.Button.NONE ? -1 : this._yb; + } else { + return -1; + } + } + + private boolean i154() { + return this._zb != null && this._zb.selected; + } +} diff --git a/src/main/java/funorb/client/lobby/ScrollBar.java b/src/main/java/funorb/client/lobby/ScrollBar.java new file mode 100644 index 0000000..5132e16 --- /dev/null +++ b/src/main/java/funorb/client/lobby/ScrollBar.java @@ -0,0 +1,211 @@ +package funorb.client.lobby; + +import funorb.awt.MouseState; +import funorb.shatteredplans.client.JagexApplet; + +public final class ScrollBar extends Component> { + private final Component> track; + private final Component upButton; + private final Component upperSlideRegion; + private final Component lowerSlideRegion; + private final Component dragBar; + private final Component downButton; + private int repeatDelayTimer; + + public ScrollBar(final Component upButton, final Component downButton, final Component slideRegion, final Component dragBar) { + super(null); + this.upButton = new Component<>(upButton); + this.downButton = new Component<>(downButton); + this.addChild(this.upButton); + this.addChild(this.downButton); + this.track = new Component<>(null); + this.addChild(this.track); + this.upperSlideRegion = new Component<>(slideRegion); + this.lowerSlideRegion = new Component<>(slideRegion); + this.lowerSlideRegion._r = true; + this.upperSlideRegion._r = true; + this.track.addChild(this.upperSlideRegion); + this.track.addChild(this.lowerSlideRegion); + this.dragBar = new Component<>(dragBar); + this.dragBar.isDraggable = true; + this.track.addChild(this.dragBar); + } + + @SuppressWarnings("CopyConstructorMissesField") + public ScrollBar(final ScrollBar other) { + this(other.upButton, other.downButton, other.upperSlideRegion, other.dragBar); + } + + public boolean isUpperSlideRegionClicked() { + if (this.upperSlideRegion.clickButton == MouseState.Button.NONE) { + if (this.upperSlideRegion.dragButton != MouseState.Button.NONE) { + if (this.repeatDelayTimer > 0) { + --this.repeatDelayTimer; + } + + if (this.repeatDelayTimer == 0 && this.dragBar.y2 + this.dragBar._w > JagexApplet.mouseY) { + this.repeatDelayTimer = 3; + return true; + } + } + + return false; + } else { + this.repeatDelayTimer = 20; + return true; + } + } + + public int a791(final int var2, final int var3, final boolean var4) { + int var5 = 0; + final int var6 = this.track.height - this.dragBar.height; + if (var6 > 0) { + final int var7 = this.dragBar.y; + final int var8 = -var3 + var2; + var5 = (var6 / 2 + var8 * var7) / var6; + } + + if (var4) { + if (var5 < 0) { + var5 = 0; + } + + if (var5 > var2 - var3) { + var5 = var2 - var3; + } + } else { + if (-var3 + var2 < var5) { + var5 = -var3 + var2; + } + + if (var5 < 0) { + var5 = 0; + } + } + + return var5; + } + + public boolean isUpButtonClicked() { + if (this.upButton.clickButton == MouseState.Button.NONE) { + if (this.upButton.dragButton != MouseState.Button.NONE) { + if (this.repeatDelayTimer > 0) { + --this.repeatDelayTimer; + } + + if (this.repeatDelayTimer == 0) { + this.repeatDelayTimer = 3; + return true; + } + } + return false; + } else { + this.repeatDelayTimer = 20; + return true; + } + } + + public boolean isLowerSlideRegionClicked() { + if (this.lowerSlideRegion.clickButton == MouseState.Button.NONE) { + if (this.lowerSlideRegion.dragButton != MouseState.Button.NONE) { + if (this.repeatDelayTimer > 0) { + --this.repeatDelayTimer; + } + + if (this.repeatDelayTimer == 0 && JagexApplet.mouseY >= this.dragBar.y2 + this.dragBar._w + this.dragBar.height + this.dragBar._gb) { + this.repeatDelayTimer = 3; + return true; + } + } + + return false; + } else { + this.repeatDelayTimer = 20; + return true; + } + } + + @SuppressWarnings("SameParameterValue") + public void setBounds(final int x, final int y, final int width, final int height, final int viewportHeight, final int contentHeight, final int scrollPosition) { + this.x = x; + this.height = height; + this.y = y; + this.width = width; + this.updateScrollBounds(viewportHeight, contentHeight, scrollPosition); + } + + public boolean isDragBarBeingDragged() { + return this.dragBar.dragButton != MouseState.Button.NONE; + } + + public boolean isDownButtonClicked() { + if (this.downButton.clickButton == MouseState.Button.NONE) { + if (this.downButton.dragButton != MouseState.Button.NONE) { + if (this.repeatDelayTimer > 0) { + --this.repeatDelayTimer; + } + + if (this.repeatDelayTimer == 0) { + this.repeatDelayTimer = 3; + return true; + } + } + + return false; + } else { + this.repeatDelayTimer = 20; + return true; + } + } + + public void updateScrollBounds(final int viewportHeight, final int contentHeight, final int scrollPosition) { + final int trackStart; + final int trackEnd; + if (this.width * 2 <= this.height) { + trackStart = this.width; + trackEnd = this.height - this.width; + } else { + trackStart = trackEnd = this.height / 2; + } + + final int trackHeight = trackEnd - trackStart; + int dragBarHeight = trackHeight; + if (contentHeight > 0) { + dragBarHeight = Math.min(Math.max(this.width, trackHeight * viewportHeight / contentHeight), trackHeight); + } + + final int overflowHeight = contentHeight - viewportHeight; + final int visibleTrackHeight = trackHeight - dragBarHeight; + int dragBarStart = 0; + if (overflowHeight > 0) { + dragBarStart = (scrollPosition * visibleTrackHeight + overflowHeight / 2) / overflowHeight; + } + + final int upperRegionHeight = dragBarStart + dragBarHeight / 2; + this.upButton.height = trackStart; + this.upButton.x = 0; + this.upButton.y = 0; + this.upButton.width = this.width; + this.downButton.x = 0; + this.downButton.y = trackEnd; + this.downButton.width = this.width; + this.downButton.height = this.height - trackEnd; + this.track.x = 0; + this.track.y = trackStart; + this.track.width = this.width; + this.track.height = trackHeight; + this.upperSlideRegion.height = upperRegionHeight; + this.upperSlideRegion.width = this.width; + this.upperSlideRegion.x = 0; + this.upperSlideRegion.y = 0; + this.lowerSlideRegion.height = trackHeight - upperRegionHeight; + this.lowerSlideRegion.y = upperRegionHeight; + this.lowerSlideRegion.x = 0; + this.lowerSlideRegion.width = this.width; + this.upButton.enabled = this.downButton.enabled = this.track.enabled = contentHeight > viewportHeight; + this.dragBar.x = 0; + this.dragBar.y = dragBarStart; + this.dragBar.width = this.width; + this.dragBar.height = dragBarHeight; + } +} diff --git a/src/main/java/funorb/client/lobby/ScrollPane.java b/src/main/java/funorb/client/lobby/ScrollPane.java new file mode 100644 index 0000000..cd0549b --- /dev/null +++ b/src/main/java/funorb/client/lobby/ScrollPane.java @@ -0,0 +1,95 @@ +package funorb.client.lobby; + +import funorb.commonui.kj_; + +public final class ScrollPane> extends Component> { + public final Component content; + public final Component> viewport; + public final ScrollBar scrollBar; + + public ScrollPane(final Component content, final Component viewportAttrsSrc, final ScrollBar scrollBar) { + super(null); + this.viewport = new Component<>(viewportAttrsSrc); + this.scrollBar = new ScrollBar(scrollBar); + this.addChild(this.viewport); + this.addChild(this.scrollBar); + this.content = content; + this.viewport.addChild(content); + } + + public static kj_ a705(final boolean var0) { + final kj_ var1 = new kj_(true); + var1._b = var0; + return var1; + } + + private void processScrollBar(final int mouseWheelRotation, final int buttonScrollAmount, final int slideRegionScrollAmount, final boolean var2) { + if (this.scrollBar.isUpButtonClicked()) { + this.content._w += buttonScrollAmount; + } + if (this.scrollBar.isDownButtonClicked()) { + this.content._w -= buttonScrollAmount; + } + if (this.scrollBar.isUpperSlideRegionClicked()) { + this.content._w += slideRegionScrollAmount; + } + if (this.scrollBar.isLowerSlideRegionClicked()) { + this.content._w -= slideRegionScrollAmount; + } + if (this.isMouseOverTarget) { + this.content._w -= mouseWheelRotation; + } + + if (var2) { + if (this.content._w + this.content.y > 0) { + this.content._w = -this.content.y; + } + + if (-this.viewport.height + this.content._gb + this.content.height < -(this.content.y + this.content._w)) { + this.content._w = -(this.content.height + this.content._gb - this.viewport.height) - this.content.y; + } + } else { + if (-(this.content._w + this.content.y) > this.content.height + this.content._gb - this.viewport.height) { + this.content._w = -this.content.y - (-this.viewport.height + this.content._gb + this.content.height); + } + + if (this.content.y + this.content._w > 0) { + this.content._w = -this.content.y; + } + } + + if (this.scrollBar.isDragBarBeingDragged()) { + this.content.y = -this.scrollBar.a791(this.content.height, this.viewport.height, var2); + this.content._w = 0; + } + + this.scrollBar.updateScrollBounds(this.viewport.height, this.content.height, -this.content.y); + } + + public void a795(final int mouseWheelRotationAmount, final int buttonScrollAmount) { + this.processScrollBar(mouseWheelRotationAmount, buttonScrollAmount, this.viewport.height, true); + } + + public void setBounds(final int x, final int y, final int width, final int height, final int scrollBarWidth) { + this.x = x; + this.width = width; + this.y = y; + this.height = height; + this.updateChildBounds(scrollBarWidth); + } + + public boolean processScrollInput(final boolean mouseStill, final boolean isContextMenuParent, final int buttonScrollAmount, final int mouseWheelRotationAmount) { + final boolean var8 = isContextMenuParent || (this.isMouseOverTarget && !mouseStill); + this.content.a811(this.viewport.height, var8); + this.processScrollBar(mouseWheelRotationAmount, buttonScrollAmount, this.viewport.height, false); + return var8; + } + + private void updateChildBounds(final int scrollBarWidth) { + this.viewport.height = this.height; + this.viewport.width = (this.width - scrollBarWidth) - 2; + this.content.x = 0; + this.content.width = this.width - scrollBarWidth - 2; + this.scrollBar.setBounds(this.width - scrollBarWidth, 0, scrollBarWidth, this.height, this.viewport.height, this.content.height, -this.content.y); + } +} diff --git a/src/main/java/funorb/client/lobby/TabbedPlayerList.java b/src/main/java/funorb/client/lobby/TabbedPlayerList.java new file mode 100644 index 0000000..79a36f3 --- /dev/null +++ b/src/main/java/funorb/client/lobby/TabbedPlayerList.java @@ -0,0 +1,75 @@ +package funorb.client.lobby; + +import funorb.awt.MouseState; + +public final class TabbedPlayerList extends Component> { + private final Component[] _xb; + private final Component[] _Db; + private final Component> _yb; + private int _zb; + + public TabbedPlayerList(final Component var3, final String[] var4, final Component var5, final Component[] var6) { + super(null); + this._Db = new Component[var4.length]; + this._yb = new Component<>(var5); + this._xb = var6; + + int var8; + for (var8 = 0; var4.length > var8; ++var8) { + final Component var9 = new Component<>(var3); + var9.label = var4[var8]; + this._Db[var8] = var9; + this.addChild(var9); + } + + this.addChild(this._yb); + + for (var8 = 0; var8 < var6.length; ++var8) { + this._yb.addChild(var6[var8]); + } + + this._zb = 0; + this._Db[0].selected = true; + } + + public void updateBounds(final int var1, final int var3) { + this.height = var3; + this.x = 0; + this.width = var1; + this.y = 0; + this.updateChildBounds(); + } + + public void f487() { + for (int i = 0; i < this._Db.length; ++i) { + if (this._zb != i && this._Db[i].clickButton != MouseState.Button.NONE) { + this._Db[this._zb].selected = false; + this._xb[this._zb].x += 10000; + this._zb = i; + this._Db[i].selected = true; + this._xb[i].x -= 10000; + } + } + } + + private void updateChildBounds() { + for (int var4 = 0; var4 < this._Db.length; ++var4) { + final int var5 = this.width * var4 / this._Db.length; + final int var6 = (1 + var4) * this.width / this._Db.length; + this._Db[var4].x = var5; + this._Db[var4].y = 0; + this._Db[var4].width = var6 - var5; + this._Db[var4].height = 24; + } + + this._yb.setBounds(0, 24, this.width, this.height - 24); + + for (int var4 = 0; var4 < this._xb.length; ++var4) { + this._xb[var4].setBounds(5, 5, -10 + this._yb.width, this._yb.height - 10); + if (this._zb != var4) { + final Component var10000 = this._xb[var4]; + var10000.x += 10000; + } + } + } +} diff --git a/src/main/java/funorb/client/lobby/TabbedPlayerListWrapper.java b/src/main/java/funorb/client/lobby/TabbedPlayerListWrapper.java new file mode 100644 index 0000000..c439160 --- /dev/null +++ b/src/main/java/funorb/client/lobby/TabbedPlayerListWrapper.java @@ -0,0 +1,22 @@ +package funorb.client.lobby; + +import funorb.shatteredplans.StringConstants; + +public final class TabbedPlayerListWrapper { + public final TabbedPlayerList view; + + public TabbedPlayerListWrapper(final String firstTabLabel, final Component var2) { + final String[] labels = new String[]{firstTabLabel, StringConstants.MU_CHAT_FRIENDS, StringConstants.MU_CHAT_IGNORE}; + final Component[] views = new Component[]{var2, Component.FRIEND_LIST_PANEL, Component.IGNORE_LIST}; + this.view = new TabbedPlayerList(Component.TAB_INACTIVE, labels, Component._tmt, views); + } + + public void updateBounds(final int width, final int height) { + this.view.updateBounds(width, height); + Component.SERVER_INFO_LABEL.setBounds(0, 0, Component.FRIEND_LIST_PANEL.width, Component.LABEL_HEIGHT); + Component.NAME_LABEL_2.setBounds(0, 2 + Component.LABEL_HEIGHT, -15 + (Component.FRIEND_LIST_PANEL.width - 2 - 82), 18); + Component.LOCATION_LABEL.setBounds(-95 + (Component.FRIEND_LIST_PANEL.width - 2), 2 + Component.LABEL_HEIGHT, 97, 18); + Component.FRIEND_LIST.updateBounds(0, 20 + Component.LABEL_HEIGHT + 2, Component.FRIEND_LIST_PANEL.width, Component.FRIEND_LIST_PANEL.height - Component.LABEL_HEIGHT - 22); + Component.IGNORE_LIST.updateChildBounds(); + } +} diff --git a/src/main/java/funorb/client/lobby/vm_.java b/src/main/java/funorb/client/lobby/vm_.java new file mode 100644 index 0000000..8a4c533 --- /dev/null +++ b/src/main/java/funorb/client/lobby/vm_.java @@ -0,0 +1,239 @@ +package funorb.client.lobby; + +import funorb.awt.KeyState; +import funorb.awt.MouseState; +import funorb.graphics.Font; +import funorb.graphics.Sprite; +import funorb.shatteredplans.C2SPacket; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.JagexApplet; +import funorb.shatteredplans.client.Menu; +import funorb.shatteredplans.client.ShatteredPlansClient; +import funorb.util.PseudoMonotonicClock; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; + +public final class vm_ extends Component> { + public static String _ahS; + public static long _aco; + public static Sprite _kflc; + private final int _xb; + private final int _Qb; + private final ActionButton[] _Kb; + private final int _Pb; + private final char[] _zb; + private final int[] _Hb; + private final vm_[] _yb; + private int _Eb; + private vm_ _Ob; + private int _Mb; + private int _Ib; + private int _Db; + private int _Gb = -1; + + public vm_(final Component var3, final Component var4, final Component var5, final vm_[] var6, final int[] var7, final String[] var8, final char[] var9) { + super(var3); + this._Hb = var7; + this._zb = var9; + this._yb = var6; + this._Pb = this._Hb.length; + final Font var10 = var5.font; + this._Qb = var10.descent + 2 + var10.ascent; + this._xb = this._Qb * this._Pb; + this._Kb = new ActionButton[this._Pb]; + this._Ib = 0; + final String var11 = ""; + final String var12 = ""; + + for (int var13 = 0; this._Pb > var13; ++var13) { + if (this._zb[var13] > 0) { + var8[var13] = var11 + String.valueOf(this._zb[var13]).toUpperCase() + ": " + var12 + var8[var13]; + } + + Sprite var14 = null; + if (this._yb[var13] != null || this._Hb[var13] == -1) { + var14 = _kflc; + } + + this._Kb[var13] = new ActionButton(var4, var5, var14, var8[var13]); + this.addChild(this._Kb[var13]); + final int var15 = var10.measureLineWidth(var8[var13]); + if (this._Ib < var15) { + this._Ib = var15; + } + } + + this._Ib += _kflc.offsetX + 10; + this.c540(12); + } + + public static int a827(final String var0) { + return Menu.FONT.measureLineWidth(var0); + } + + private static void a345un(final String var0, final long var1, final @NotNull ChatMessage.Channel var3, final int var4) { + ShatteredPlansClient._cvcn = true; + ShatteredPlansClient._vsd = var4; + _aco = var1; + _ahS = var0; + ShatteredPlansClient._tlr = var3; + } + + private static void a150gs() { + ShatteredPlansClient._tkz = PseudoMonotonicClock.currentTimeMillis(); + ShatteredPlansClient._vjC = 0; + } + + public void close() { + for (final ActionButton button : this._Kb) { + button.clickButton = MouseState.Button.NONE; + button.selected = false; + } + + if (this._Ob != null) { + this._Ob.close(); + _uaf.children.remove(this._Ob); + } + + this._Ob = null; + this._Gb = -1; + this.c540(12); + } + + public void a669(final int var2, final int var3, final int var4, final int var5, final int var6) { + this._Eb = this._Ib + var2 * 2; + this.setBounds(var4, var6 - this._xb, this._Eb, this._xb); + if (this._Mb != var3) { + this._Mb = var3; + this.c540(this._Db); + } + + int var7; + for (var7 = 0; this._Pb > var7; ++var7) { + this._Kb[var7].a370(this._Qb, this._Kb[var7].y, var2, var5, this._Eb, 0); + } + + if (this._Gb != -1 && this._yb[this._Gb] != null) { + var7 = this._yb[this._Gb]._Pb; + + int var8 = this._Qb * (var7 + this._Gb) + this.y; + while (var6 < var8) { + var8 -= this._Qb; + } + + this._yb[this._Gb].a669(var2, this._Kb[this._Gb].y2, var4 + this._Eb, var5, var8); + } + + } + + public int g474() { + return this._Eb + (this._Ob != null ? this._Ob.g474() : 0); + } + + public void a599() { + for (int var4 = 0; this._Kb.length > var4; ++var4) { + final ActionButton var5 = this._Kb[var4]; + if (var5.clickButton == MouseState.Button.LEFT) { + this.a115(var4); + var5.selected = this._Gb == var4; + } + } + + if (this._Gb != -1) { + final vm_ var6 = this._yb[this._Gb]; + if (var6 != null) { + var6.a599(); + } + } + + if (this._Db > 0) { + this.c540(this._Db - 1); + } + + } + + private void a115(final int var3) { + if (this._Gb == var3) { + this.close(); + this.c540(0); + } else if (this._yb[var3] != null) { + this.close(); + this.c540(0); + this._Gb = var3; + this._Ob = this._yb[this._Gb]; + _uaf.addChild(this._Ob); + this._Ob.c540(12); + } else if (this._Hb[var3] == -1) { + QuickChatHelpPanel.openInstance = new QuickChatHelpPanel(Component.TAB_ACTIVE, CLOSE_BUTTON, Component.LABEL); + ShatteredPlansClient.closeQuickChat(); + } else { + final int var5 = this._Hb[var3] | 0x8000; + ChatMessage.Channel var6 = ShatteredPlansClient.currentChatChannel; + if (var6 == ChatMessage.Channel.LOBBY && ShatteredPlansClient.unratedLobbyRoom != null) { + var6 = ChatMessage.Channel.ROOM; + } + + if (ContextMenu.getChatChannelFilter(var6) == ChatMessage.FilterLevel.NONE) { + ContextMenu.setChatFilter(var6, ChatMessage.FilterLevel.FRIENDS); + } + + C2SPacket.sendQuickChatMessage(ShatteredPlansClient.currentChatChannel, ContextMenu.recipientPlayerName, var5); + a345un(ContextMenu.recipientPlayerName, ContextMenu.recipientPlayerId, ShatteredPlansClient.currentChatChannel, var5); + ShatteredPlansClient.closeQuickChat(); + a150gs(); + } + + } + + private void c540(final int var2) { + this._Db = var2; + for (int var5 = 0; this._Pb > var5; ++var5) { + final int var3 = this._Qb * var5; + final int var4 = this._Db * this._Db; + this._Kb[var5].y = ((-this.y2 + this._Mb) * var4 + var3 * (144 - var4)) / 144; + } + } + + public boolean f491() { + boolean var2 = Arrays.stream(this._Kb).anyMatch(var5 -> var5.clickButton != MouseState.Button.NONE); + + if (!var2 && this._Gb != -1 && this._yb[this._Gb] != null) { + var2 = this._yb[this._Gb].f491(); + } + + return var2; + } + + public boolean a777() { + final boolean var4 = JagexApplet.lastTypedKeyCode == KeyState.Code.BACKSPACE; + if (this._Ob != null) { + if (var4 && this._Ob._Gb == -1) { + this.close(); + this.c540(0); + return true; + } else { + return this._Ob.a777(); + } + } else if (this == ShatteredPlansClient._dmrh && var4) { + ShatteredPlansClient.closeQuickChat(); + return true; + } else { + char var5 = JagexApplet.lastTypedKeyChar; + if (var5 > 0) { + if (var5 == StringConstants.KEYCHAR_THE_CHARACTER_UNDER_QUESTION_MARK) { + var5 = '?'; + } + + for (int var6 = 0; var6 < this._zb.length; ++var6) { + if (var5 == this._zb[var6]) { + this.a115(var6); + return true; + } + } + } + + return false; + } + } +} diff --git a/src/main/java/funorb/client/pa_.java b/src/main/java/funorb/client/pa_.java new file mode 100644 index 0000000..69a666a --- /dev/null +++ b/src/main/java/funorb/client/pa_.java @@ -0,0 +1,69 @@ +package funorb.client; + +import java.io.IOException; +import java.net.Proxy; +import java.net.Proxy.Type; +import java.net.ProxySelector; +import java.net.Socket; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +public final class pa_ extends li_ { + private final ProxySelector _g = ProxySelector.getDefault(); + + private pa_() {} + + public static li_ a287ho(final int var0, final String var1) { + final pa_ var2 = new pa_(); + var2._a = var0; + var2._f = var1; + return var2; + } + + private Socket a837(final Proxy var2) throws IOException { + if (var2.type() == Type.DIRECT) { + return this.a693(); + } else { + return null; + } + } + + @Override + public Socket b693() throws IOException { + final boolean var2 = Boolean.parseBoolean(System.getProperty("java.net.useSystemProxies")); + if (!var2) { + System.setProperty("java.net.useSystemProxies", "true"); + } + + final boolean var5 = this._a == 443; + + final List var3; + final List var4; + try { + var3 = this._g.select(new URI((var5 ? "https" : "http") + "://" + this._f)); + var4 = this._g.select(new URI((!var5 ? "https" : "http") + "://" + this._f)); + } catch (final URISyntaxException var15) { + return this.a693(); + } + + var3.addAll(var4); + final Object[] var6 = var3.toArray(); + int var9 = 0; + + for (; var6.length > var9; ++var9) { + final Object var10 = var6[var9]; + final Proxy var11 = (Proxy) var10; + + try { + final Socket var12 = this.a837(var11); + if (var12 != null) { + return var12; + } + } catch (final IOException var14) { + } + } + + return this.a693(); + } +} diff --git a/src/main/java/funorb/client/r_.java b/src/main/java/funorb/client/r_.java new file mode 100644 index 0000000..64e8295 --- /dev/null +++ b/src/main/java/funorb/client/r_.java @@ -0,0 +1,174 @@ +package funorb.client; + +import funorb.Strings; +import funorb.io.Buffer; +import funorb.shatteredplans.client.MailboxMessage; +import funorb.shatteredplans.client.MessagePumpThread; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; +import java.net.URL; + +public final class r_ implements Runnable { + private final Buffer _k; + private final MessagePumpThread _l; + private final URL _e; + private MailboxMessage _b; + private DataInputStream _g; + private int _h; + private MailboxMessage _a; + private MailboxMessage _i; + + public r_(final MessagePumpThread var1, final URL var2) { + this._e = var2; + this._l = var1; + this._k = new Buffer(5000); + } + + @Override + protected void finalize() { + if (this._b != null) { + if (this._b.response != null) { + try { + ((DataInputStream) this._b.response).close(); + } catch (final Exception var4) { + } + } + + this._b = null; + } + + if (this._i != null) { + if (this._i.response != null) { + try { + ((Socket) this._i.response).close(); + } catch (final Exception var3) { + } + } + + this._i = null; + } + + if (this._g != null) { + try { + this._g.close(); + } catch (final Exception var2) { + } + + this._g = null; + } + + this._a = null; + } + + @Override + public void run() { + while (true) { + try { + if (this._k.data.length > this._k.pos) { + final int var1 = this._g.read(this._k.data, this._k.pos, this._k.data.length - this._k.pos); + if (var1 >= 0) { + this._k.pos += var1; + continue; + } + } + + if (this._k.pos == this._k.data.length) { + throw new Exception("HG1: " + this._k.data.length + " " + this._e); + } + + synchronized (this) { + //noinspection FinalizeCalledExplicitly + this.finalize(); + this._h = 3; + } + } catch (final Exception var6) { + synchronized (this) { + //noinspection FinalizeCalledExplicitly + this.finalize(); + ++this._h; + } + } + + return; + } + } + + public synchronized boolean b154() { + if (this._h < 2) { + if (this._h == 0) { + if (this._b == null) { + this._b = this._l.sendOpenUrlStreamMessage(this._e); + } + + if (this._b.status == MailboxMessage.Status.PENDING) { + return false; + } + + if (this._b.status != MailboxMessage.Status.SUCCESS) { + ++this._h; + this._b = null; + return false; + } + } + + if (this._h == 1) { + if (this._i == null) { + this._i = this._l.sendOpenSocketMessage(this._e.getHost(), 443); + } + + if (this._i.status == MailboxMessage.Status.PENDING) { + return false; + } + + if (this._i.status != MailboxMessage.Status.SUCCESS) { + ++this._h; + this._i = null; + return false; + } + } + + if (this._g == null) { + try { + if (this._h == 0) { + this._g = (DataInputStream) this._b.response; + } + + if (this._h == 1) { + final Socket var2 = (Socket) this._i.response; + var2.setSoTimeout(10000); + final OutputStream var3 = var2.getOutputStream(); + var3.write(17); + var3.write(Strings.encode1252String("JAGGRAB " + this._e.getFile() + "\n\n")); + this._g = new DataInputStream(var2.getInputStream()); + } + + this._k.pos = 0; + } catch (final IOException var4) { + //noinspection FinalizeCalledExplicitly + this.finalize(); + ++this._h; + } + } + + if (this._a == null) { + this._a = this._l.sendSpawnThreadMessage(this, 5); + } + + if (this._a.status != MailboxMessage.Status.PENDING) { + if (this._a.status != MailboxMessage.Status.SUCCESS) { + //noinspection FinalizeCalledExplicitly + this.finalize(); + ++this._h; + } + + } + return false; + } else { + return true; + } + } + +} diff --git a/src/main/java/funorb/commonui/AbstractTextField.java b/src/main/java/funorb/commonui/AbstractTextField.java new file mode 100644 index 0000000..5b51471 --- /dev/null +++ b/src/main/java/funorb/commonui/AbstractTextField.java @@ -0,0 +1,359 @@ +package funorb.commonui; + +import funorb.awt.KeyState; +import funorb.commonui.listener.ComponentListener; +import funorb.commonui.listener.TextFieldListener; +import funorb.commonui.renderer.ComponentRenderer; +import funorb.commonui.renderer.ITextRenderer; +import funorb.shatteredplans.client.JagexApplet; +import funorb.util.PseudoMonotonicClock; +import org.intellij.lang.annotations.MagicConstant; + +import java.awt.Toolkit; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; + +public class AbstractTextField extends Button { + private final int _O; + private final boolean _M; + private int _H; + private int _R = -1; + private int _N; + private long _F = 0L; + private boolean _P = false; + private long _Q; + + protected AbstractTextField(final String text, final ComponentRenderer renderer, final ComponentListener listener, final int var3) { + super(text, renderer, listener); + this._O = var3; + this.a676(text, true); + this._M = true; + this._Q = PseudoMonotonicClock.currentTimeMillis(); + } + + private void k423() { + final int var2; + if (this._H != this._N) { + var2 = Math.min(this._N, this._H); + final int var3 = Math.max(this._H, this._N); + this._N = var2; + this._H = var2; + this.text = this.text.substring(0, var2) + this.text.substring(var3); + this.i150(); + } + } + + private void h423() { + this.h150(); + this.k423(); + } + + private void a407(final String var2) { + if (this._O != -1) { + assert this._O - this.text.length() >= 0; + return; + } + + if (this._H == this.text.length()) { + this.text = this.text + var2; + } else { + this.text = this.text.substring(0, this._H) + var2 + this.text.substring(this._H); + } + + this._H += var2.length(); + this._N = this._H; + this.i150(); + } + + public final void e487() { + this._N = 0; + this._H = 0; + this.text = ""; + this.i150(); + } + + @Override + public final boolean a446(final int var1, final int var2, final int var4, final int var5, final int var6, final Component var7) { + if (super.a446(var1, var2, var4, var5, var6, var7) && this.renderer instanceof ITextRenderer) { + final int var8 = ((ITextRenderer) this.renderer).a242(var5, JagexApplet.mouseX, var6, this, JagexApplet.mouseY); + this.a093(var8 != -1 ? var8 : 0); + final long var10 = PseudoMonotonicClock.currentTimeMillis(); + this._P = -this._F + var10 < 250L; + if (this._P) { + this._N = this.g410(); + this._H = this.a137(); + if (this._H > 0 && this.text.charAt(this._H - 1) == ' ') { + --this._H; + } + + this._R = this._H; + } + + this._F = var10; + return true; + } else { + return false; + } + } + + private void j423() { + if (this._M) { + if (this.renderer instanceof ITextRenderer var2) { + final AbstractTextLayout var3 = var2.updateLayout(this); + final int var4 = var3.getWidth(); + final int var5 = var2.getAvailableWidth(this); + final int var6 = var2.a474() >> 1; + if (var4 < -var6 + var5) { + this._l = 0; + this._h = 0; + } else { + final int var7 = this._h + var3.a527(this._H); + if (-var6 + var5 >= var7) { + if (var6 > var7) { + this._h += -var7 + var6; + } + } else { + this._h = this._h - var6 + (var5 - var7); + } + + if (this._h <= 0) { + if (this._h < -var5 + var6) { + this._h = -var5 + var6; + } + } else { + this._h = 0; + } + + } + } + } else { + this._l = 0; + this._h = 0; + } + } + + @Override + public final void draw(final int x, final int y) { + if (this.renderer != null) { + this.renderer.draw(this, x, y, this.enabled); + if (this.renderer instanceof ITextRenderer var5) { + if (this._H != this._N) { + var5.a132(this._N, y, x, this._H, this); + } + + final long var6 = PseudoMonotonicClock.currentTimeMillis(); + if ((var6 - this._Q) % 1000L < 500L) { + var5.a403(this._H, x, y, this); + } + } + } + } + + private void a093(final int var2) { + this._H = var2; + if (!JagexApplet.keysDown[KeyState.Code.SHIFT]) { + this._N = this._H; + } + } + + @Override + public final boolean a686(@MagicConstant(valuesFromClass = KeyState.Code.class) final int keyCode, final char keyChar, final Component var4) { + + this._Q = PseudoMonotonicClock.currentTimeMillis(); + if (keyChar == '<' || keyChar == '>') { + return false; + } else if (keyChar >= ' ' && keyChar <= '~') { + if (this._H != this._N) { + this.k423(); + } + + if (this._O == -1 || this.text.length() < this._O) { + if (this._H >= this.text.length()) { + this.text = this.text + keyChar; + this._N = this._H = this.text.length(); + } else { + this.text = this.text.substring(0, this._H) + keyChar + this.text.substring(this._H); + ++this._H; + this._N = this._H; + } + + this.i150(); + } + + return true; + } else { + if (keyCode == KeyState.Code.BACKSPACE) { + if (this._N != this._H) { + this.k423(); + return true; + } + + if (this._H > 0) { + this._N = this._H - 1; + this.k423(); + return true; + } + } else if (keyCode == KeyState.Code.DELETE) { + if (this._N != this._H) { + this.k423(); + return true; + } + + if (this._H < this.text.length()) { + this._N = 1 + this._H; + this.k423(); + return true; + } + } else { + if (keyCode == KeyState.Code.ESCAPE) { + this.e487(); + return true; + } + + if (keyCode != KeyState.Code.LEFT) { + if (keyCode != KeyState.Code.RIGHT) { + if (keyCode == KeyState.Code.HOME) { + this.a093(0); + return true; + } + + if (keyCode == KeyState.Code.END) { + this.a093(this.text.length()); + return true; + } + + if (keyCode == KeyState.Code.ENTER) { + this.handleEnterKey(); + return true; + } + + if (JagexApplet.keysDown[KeyState.Code.CONTROL] && keyCode == KeyState.Code.LETTER_X) { + this.h423(); + return true; + } + + if (JagexApplet.keysDown[KeyState.Code.CONTROL] && keyCode == KeyState.Code.LETTER_C) { + this.h150(); + return true; + } + + if (JagexApplet.keysDown[KeyState.Code.CONTROL] && keyCode == KeyState.Code.LETTER_V) { + this.m423(); + return true; + } + } else if (this._H < this.text.length()) { + this.a093(JagexApplet.keysDown[KeyState.Code.CONTROL] ? this.a137() : 1 + this._H); + return true; + } + } else if (this._H > 0) { + this.a093(!JagexApplet.keysDown[KeyState.Code.CONTROL] ? this._H - 1 : this.g410()); + return true; + } + } + + return false; + } + } + + private int a137() { + final int var2 = this.text.length(); + if (var2 == this._H) { + return this._H; + } else { + int var3; + var3 = 1 + this._H; + while (var2 > var3 && this.text.charAt(var3 - 1) != ' ') { + ++var3; + } + return var3; + } + } + + @Override + public void tick(final int x, final int y, final Component root) { + super.tick(x, y, root); + this.j423(); + if (this._o == 1) { + if (this.renderer instanceof ITextRenderer var5) { + int var6 = var5.a242(x, JagexApplet.mouseX, y, this, JagexApplet.mouseY); + if (var6 != -1) { + if (this._P && this._R > var6 && var6 > this._N) { + var6 = this._R; + } + + this._H = var6; + } + } + + this._Q = PseudoMonotonicClock.currentTimeMillis(); + } + + } + + protected void i150() { + if (this.listener instanceof TextFieldListener) { + ((TextFieldListener) this.listener).handleTextFieldChanged(); + } + } + + public final void a676(String var2, final boolean var3) { + if (var2 == null) { + var2 = ""; + } + + this.text = var2; + final int var5 = var2.length(); + if (this._O != -1 && this._O < var5) { + this.text = this.text.substring(0, this._O); + } + + this._H = this._N = this.text.length(); + if (!var3) { + this.i150(); + } + + } + + private String l983() { + final int var2 = Math.min(this._H, this._N); + final int var3 = Math.max(this._N, this._H); + return this.text.substring(var2, var3); + } + + private void m423() { + try { + final String var2 = (String) Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null).getTransferData(DataFlavor.stringFlavor); + this.k423(); + this.a407(var2); + } catch (final Exception var3) { + } + + } + + private void h150() { + final String var2 = this.l983(); + if (var2.length() > 0) { + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(this.l983()), null); + } + + } + + private int g410() { + if (this._H == 0) { + return this._H; + } else { + int var2 = this._H - 1; + while (var2 > 0 && this.text.charAt(var2 - 1) != ' ') { + --var2; + } + + return var2; + } + } + + private void handleEnterKey() { + if (this.listener instanceof TextFieldListener l) { + l.handleTextFieldEnterPressed(this); + } + } +} diff --git a/src/main/java/funorb/commonui/AbstractTextLayout.java b/src/main/java/funorb/commonui/AbstractTextLayout.java new file mode 100644 index 0000000..5d3a2d4 --- /dev/null +++ b/src/main/java/funorb/commonui/AbstractTextLayout.java @@ -0,0 +1,109 @@ +package funorb.commonui; + +import java.util.Arrays; +import java.util.Objects; + +public abstract class AbstractTextLayout { + public TextLineMetrics[] lineMetrics; + + public final int a543(int var2) { + int var3 = 0; + + while (this.lineMetrics.length > var3) { + final TextLineMetrics var4 = this.lineMetrics[var3]; + if (var4._b.length > var2) { + return var3; + } + + var2 -= var4.getCharCount(); + ++var3; + } + + return this.lineMetrics.length; + } + + public final int b137() { + return this.lineMetrics != null && this.lineMetrics.length > 0 ? this.lineMetrics[this.lineMetrics.length - 1].bottom - this.lineMetrics[0].top : 0; + } + + public final int getWidth() { + if (this.lineMetrics == null) { + return -1; + } else { + return Arrays.stream(this.lineMetrics).filter(Objects::nonNull) + .mapToInt(TextLineMetrics::getWidth).max() + .orElse(-1); + } + } + + protected final int a947(final int var2, final int var3, final String var4) { + int var5 = 0; + boolean var6 = false; + final int var7 = var4.length(); + + for (int var8 = 0; var7 > var8; ++var8) { + final char var9 = var4.charAt(var8); + if (var9 == '<') { + var6 = true; + } else if (var9 == '>') { + var6 = false; + } else if (!var6 && var9 == ' ') { + ++var5; + } + } + + if (var5 <= 0) { + return 0; + } else { + return (var2 - var3 << 8) / var5; + } + } + + public final int a313(final int var1, final int var3) { + if (this.lineMetrics != null && this.lineMetrics.length != 0 && this.lineMetrics[0].top <= var3) { + if (this.lineMetrics[this.lineMetrics.length - 1].bottom >= var3) { + if (this.lineMetrics.length == 1) { + return this.lineMetrics[0].a527(var1); + } else { + int var4 = 0; + + for (final TextLineMetrics var6 : this.lineMetrics) { + if (var3 >= var6.top && var6.bottom >= var3) { + final int var7 = var6.a527(var1); + if (var7 != -1) { + return var4 + var7; + } + + return -1; + } + + var4 += var6.getCharCount(); + } + + return -1; + } + } else { + return -1; + } + } else { + return -1; + } + } + + public final int a527(int var2) { + final TextLineMetrics[] var3 = this.lineMetrics; + int var4 = 0; + + while (var3.length > var4) { + final TextLineMetrics var5 = var3[var4]; + if (var5._b.length > var2) { + return var5._b[var2]; + } + + var2 -= var5.getCharCount(); + ++var4; + } + + return 0; + } +} diff --git a/src/main/java/funorb/commonui/AccountPage.java b/src/main/java/funorb/commonui/AccountPage.java new file mode 100644 index 0000000..1ef59ad --- /dev/null +++ b/src/main/java/funorb/commonui/AccountPage.java @@ -0,0 +1,133 @@ +package funorb.commonui; + +import funorb.awt.KeyState; +import funorb.commonui.form.LoginForm; +import funorb.commonui.listener.ButtonListener; +import funorb.graphics.Font; +import funorb.shatteredplans.client.JagexApplet; +import funorb.client.JagexBaseApplet; +import funorb.shatteredplans.StringConstants; + +public class AccountPage extends FormNavigationPage implements ButtonListener { + private final boolean _vb; + private final ProgressBar _yb; + private final boolean _tb; + private final Font _ub; + private boolean _sb = false; + private boolean _wb; + + public AccountPage(final NavigationRoot var1, final Font var2, final String var3, final boolean var4, final boolean var5) { + super(var1, new cf_(null, var2, var3), 77, 10, 10); + this._tb = var4; + this._vb = var5; + this._wb = false; + this._ub = var2; + this._yb = new ProgressBar(); + this._yb.animateStripes = true; + this.addChild(this._yb); + } + + private static void a150nb() { + if (CommonUI._nlb) { + if (CommonUI._jiG != null) { + CommonUI._jiG.i423(); + } + + final String var1 = l738w(); + LoginForm._noe = new LoginForm(var1, true, false, false); + CommonUI.root.pushChild(CommonUI._aef); + CommonUI._aef.b952(LoginForm._noe); + CommonUI._aef.n150(); + } else { + throw new IllegalStateException(); + } + } + + private static String l738w() { + String var1 = ""; + if (LoginForm._noe != null) { + var1 = LoginForm._noe.d791(); + } + + if (var1.length() == 0) { + var1 = a738id(); + } + + if (var1.length() == 0) { + var1 = StringConstants.DEFAULT_PLAYER_NAME; + } + + return var1; + } + + private static String a738id() { + return JagexApplet.playerDisplayName == null ? "" : JagexApplet.playerDisplayName; + } + + public final void p150() { + this._yb.setColor(ProgressBar.SUCCESS_COLOR); + final cf_ var2 = new cf_(this, this._ub, StringConstants.CONNECTION_RESTORED); + var2.a966(StringConstants.RETURN_TO_GAME, CommonUI.TickResult.RETURN_TO_GAME); + this.b952(var2); + } + + public final void i423() { + if (this.isAlive) { + this.isAlive = false; + if (this._tb) { + a150nb(); + } else if (this._vb) { + LoginForm.a667ce(JagexApplet._aeg); + } + } + } + + @Override + public void handleButtonClicked(final Button button) { + if (this._sb) { + CommonUI._crb = CommonUI.TickResult.LOGGING_IN; + this.i423(); + } else { + JagexApplet.a808bp("tochangedisplayname.ws", JagexBaseApplet.getInstance()); + } + } + + @Override + public final boolean a686(final int keyCode, final char keyChar, final Component var4) { + if (keyCode == KeyState.Code.ESCAPE) { + this.i423(); + return true; + } else { + return super.a686(keyCode, keyChar, var4); + } + } + + public final void a503(final String var1, final int var2) { + if (!this._wb) { + this._sb = var2 == 256; + this._wb = true; + this._yb.setColor(ProgressBar.FAILURE_COLOR); + final cf_ var4 = new cf_(this, this._ub, var1); + if (var2 == 5) { + var4.a966(StringConstants.RELOAD_GAME, CommonUI.TickResult.RELOAD); + var4.a966(StringConstants.QUIT_TO_WEBSITE, CommonUI.TickResult.QUIT_TO_WEBSITE); + } else if (var2 == 256) { + var4.a700(this, StringConstants.RETRY); + } else { + var4.a966(this._tb ? StringConstants.RETRY : StringConstants.BACK, null); + } + + if (var2 == 3) { + var4.a966(StringConstants.TO_SERVER_LIST, CommonUI.TickResult.TO_SERVER_LIST); + } else if (var2 == 4) { + var4.a966(StringConstants.PLAY_FREE_VERSION, CommonUI.TickResult.PLAY_FREE_VERSION); + } else if (var2 == 6) { + var4.a966(StringConstants.TO_CUSTOMER_SUPPORT, CommonUI.TickResult.TO_CUSTOMER_SUPPORT); + } else if (var2 == 9) { + var4.a700(this, StringConstants.CHANGE_DISPLAY_NAME); + } + + this.b952(var4); + } + } +} diff --git a/src/main/java/funorb/commonui/Button.java b/src/main/java/funorb/commonui/Button.java new file mode 100644 index 0000000..5702429 --- /dev/null +++ b/src/main/java/funorb/commonui/Button.java @@ -0,0 +1,195 @@ +package funorb.commonui; + +import funorb.awt.KeyState; +import funorb.awt.MouseState; +import funorb.commonui.listener.ComponentListener; +import funorb.commonui.listener.ButtonListener; +import funorb.commonui.renderer.ButtonRenderer; +import funorb.commonui.renderer.ComponentRenderer; +import funorb.graphics.Drawing; +import funorb.shatteredplans.client.JagexApplet; +import org.intellij.lang.annotations.MagicConstant; + +import java.util.Hashtable; + +public class Button extends Component { + private final boolean _B; + public boolean active; + public boolean enabled; + private boolean focused; + + public Button(final String text, final ComponentListener listener) { + this(text, new ButtonRenderer(), listener); + } + + public Button(final String text, final ComponentRenderer renderer, final ComponentListener listener) { + super(text, renderer, listener); + this._B = true; + this.focused = false; + this.enabled = true; + } + + protected Button() { + this._B = true; + this.focused = false; + this.enabled = true; + this.renderer = null; + } + + public static void drawFocusRect(final int x, final int y, final int width, final int height) { + final int var5 = x + width; + final int var6 = height + y; + final int var7 = Math.max(x, Drawing.left); + final int var8 = Math.max(Drawing.top, y); + final int var9 = Math.min(Drawing.right, var5); + + final int var10 = Math.min(Drawing.bottom, var6); + int var11; + int var12; + if (Drawing.left <= x && Drawing.right > x) { + var11 = Drawing.width * var8 + x; + var12 = var10 + 1 - var8 >> 1; + + while (true) { + --var12; + if (var12 < 0) { + break; + } + + Drawing.screenBuffer[var11] = Drawing.WHITE; + var11 += Drawing.width * 2; + } + } + + if (y >= Drawing.top && Drawing.bottom > var6) { + var11 = Drawing.pixelIndex(var7, y); + var12 = -var7 + 1 + var9 >> 1; + + while (true) { + --var12; + if (var12 < 0) { + break; + } + + Drawing.screenBuffer[var11] = Drawing.WHITE; + var11 += 2; + } + } + + if (Drawing.left <= var5 && var5 < Drawing.right) { + var11 = Drawing.width * ((1 & var5 - x) + var8) + var5; + var12 = 1 - (-var10 + var8) >> 1; + + while (true) { + --var12; + if (var12 < 0) { + break; + } + + Drawing.screenBuffer[var11] = Drawing.WHITE; + var11 += Drawing.width * 2; + } + } + + if (y >= Drawing.top && Drawing.bottom > var6) { + var11 = (1 & var6 - y) + var6 * Drawing.width + var7; + var12 = -var7 + 1 + var9 >> 1; + + while (true) { + --var12; + if (var12 < 0) { + break; + } + + Drawing.screenBuffer[var11] = Drawing.WHITE; + var11 += 2; + } + } + + } + + @Override + public final StringBuilder buildDebugString(final Hashtable cycles, final int nestingLevel, final StringBuilder builder) { + if (this.debugStringCycleCheck(cycles, builder)) { + this.putDefaultDebugString(cycles, nestingLevel, builder); + if (this.active) { + builder.append(" active"); + } + + if (!this.enabled) { + builder.append(" disabled"); + } + } + + return builder; + } + + @Override + public boolean focus(final Component previouslyFocused) { + if (this.enabled && this._B) { + previouslyFocused.unfocus(); + this.focused = true; + return true; + } else { + return false; + } + } + + @Override + public final boolean isFocused() { + return this.focused; + } + + @Override + public boolean a446(final int var1, final int var2, final int var4, final int var5, final int var6, final Component var7) { + if (this.enabled && this.a046(var2, var4, var6, var5)) { + this.focus(var7); + this._o = var1; + + return true; + } else { + return false; + } + } + + @Override + public final void unfocus() { + if (this.focused) { + this.focused = false; + } + } + + @Override + public void tick(final int x, final int y, final Component root) { + super.tick(x, y, root); + if (this._o != 0 && JagexApplet.mouseButtonDown != this._o) { + if (this.a046(JagexApplet.mouseX, JagexApplet.mouseY, y, x) && JagexApplet.mouseButtonDown == MouseState.Button.NONE) { + this.handleClicked(this._o, JagexApplet.mouseX - x, -y + JagexApplet.mouseY); + } + + this.a132(JagexApplet.mouseX, y, x, JagexApplet.mouseY, root); + } + + } + + @Override + public boolean a686(@MagicConstant(valuesFromClass = KeyState.Code.class) final int keyCode, final char keyChar, final Component var4) { + if (!this.isFocused() || keyCode != KeyState.Code.ENTER && keyCode != KeyState.Code.SPACE) { + return false; + } else { + this.handleClicked(1, -1, -1); + return true; + } + } + + protected void handleClicked(final int var1, final int var2, final int var3) { + if (this.listener != null && this.listener instanceof ButtonListener) { + ((ButtonListener) this.listener).handleButtonClicked(this); + } + } + + @Override + public final void a132(final int var1, final int var2, final int var3, final int var4, final Component var6) { + this._o = 0; + } +} diff --git a/src/main/java/funorb/commonui/Checkbox.java b/src/main/java/funorb/commonui/Checkbox.java new file mode 100644 index 0000000..d2f6567 --- /dev/null +++ b/src/main/java/funorb/commonui/Checkbox.java @@ -0,0 +1,23 @@ +package funorb.commonui; + +import funorb.commonui.renderer.CheckboxRenderer; +import funorb.commonui.renderer.ComponentRenderer; + +public final class Checkbox extends Button { + @SuppressWarnings("SameParameterValue") + public Checkbox(final boolean active) { + this(new CheckboxRenderer(), active); + } + + @SuppressWarnings("SameParameterValue") + private Checkbox(final ComponentRenderer renderer, final boolean active) { + super("", renderer, null); + this.active = active; + } + + @Override + public void handleClicked(final int var1, final int var2, final int var3) { + this.active = !this.active; + super.handleClicked(var1, var2, var3); + } +} diff --git a/src/main/java/funorb/commonui/CommonUI.java b/src/main/java/funorb/commonui/CommonUI.java new file mode 100644 index 0000000..9ae29d0 --- /dev/null +++ b/src/main/java/funorb/commonui/CommonUI.java @@ -0,0 +1,289 @@ +package funorb.commonui; + +import funorb.Strings; +import funorb.cache.ResourceLoader; +import funorb.commonui.form.CreateAccountForm; +import funorb.commonui.form.CreateDisplayNameForm; +import funorb.commonui.form.JustPlayForm; +import funorb.commonui.form.LoginForm; +import funorb.commonui.form.validator.ConfirmEmailValidator; +import funorb.graphics.Drawing; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.JagexApplet; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.Nullable; + +public final class CommonUI { + public static NavigationRoot root; + public static AccountPage _jiG; + public static FormNavigationPage _aef; + private static LoadingBar loadingBar; + + public static @Nullable TickResult _crb = null; + + private static float loadingPercent; + private static String loadingMessage; + private static String loadingNotificationMessage = null; + + private static boolean loggingIn = false; + public static boolean _nlb; + public static boolean _nsbD = false; + public static Enum1 _eel; + public static Enum1 _fjs; + + public static String enteredUsername; + public static String enteredPassword; + public static boolean loadingFailed; + public static CreateDisplayNameForm _sjb; + public static int _tfn; + + private CommonUI() {} + + + public static void load(final ResourceLoader spritesLoader, final ResourceLoader fontsLoader, final ResourceLoader dataLoader) { + ConfirmEmailValidator._wha = new ks_(""); + ConfirmEmailValidator._wha.a540(false); + Resources.load(spritesLoader, fontsLoader, dataLoader); + TooltipManager.initialize(Resources.AREZZO_14); + root = new NavigationRoot(); + switchToLogin(true, true); + _eel = Enum1.C1; + _fjs = Enum1.C1; + } + + public static TickResult tick() { + root.tickRoot(0, 0, true); + root.tick2(); + + while (JagexApplet.nextTypedKey()) { + root.keyTyped(JagexApplet.lastTypedKeyCode, JagexApplet.lastTypedKeyChar); + } + + if (_crb != null) { + final TickResult tmp = _crb; + _crb = null; + return tmp; + } else if (loggingIn) { + return TickResult.LOGGING_IN; + } else if (_fjs == Enum1.C3) { + return TickResult.R1; + } else if (ConfirmEmailValidator._wha.b154()) { + return _eel == Enum1.C3 ? TickResult.R2 : null; + } else { + return TickResult.R1; + } + } + + public static String getPassword() { + return _eel != Enum1.C3 ? enteredPassword : CreateAccountForm._G; + } + + public static void switchToLoadingScreen() { + if (root != null) { + root.switchToLoadingScreen(); + } + if (loadingBar != null) { + loadingBar.disableAnimation(); + } + if (TooltipManager.INSTANCE != null) { + TooltipManager.INSTANCE.reset(); + } + } + + public static void switchToLogin(final boolean canCreateAccount, final boolean isInitialLogin) { + f150fe(); + root.startTransitioningOut(); + LoginForm._noe = new LoginForm(enteredUsername, _nlb, canCreateAccount, isInitialLogin); + _aef = new FormNavigationPage(root, LoginForm._noe, 33, 20, 30); + root.pushChild(_aef); + } + + public static void setStateLoggingIn(final String message, final boolean var2) { + _nsbD = var2; + loggingIn = true; + _jiG = new AccountPage(root, Resources.AREZZO_14_BOLD, message, _nlb, _nsbD); + root.pushChild(_jiG); + } + + public static void handleServerDisconnect() { + if (JagexApplet.connectionState == JagexApplet.ConnectionState.CONNECTED) { + f150fe(); + _nlb = true; + root.startTransitioningOut(); + setStateLoggingIn(StringConstants.CONNECTION_LOST_RECONNECTING, false); + JagexApplet.connectionState = JagexApplet.ConnectionState.RECONNECTING; + } + loadingFailed = true; + } + + private static void f150fe() { + loggingIn = false; + _nlb = false; + _crb = null; + _eel = Enum1.C1; + _fjs = Enum1.C1; + } + + public static void handleLoginSucceeded() { + loggingIn = false; + loadingNotificationMessage = null; + if (_nlb) { + _jiG.p150(); + } else { + final int var1 = _tfn; + if (var1 > 0) { + if (var1 == 1) { + loadingNotificationMessage = StringConstants.TICKETING_ONE_UNREAD; + } else { + loadingNotificationMessage = Strings.format(StringConstants.TICKETING_X_UNREAD, Integer.toString(var1)); + } + + loadingNotificationMessage = a547lr(new CharSequence[]{loadingNotificationMessage, "
", StringConstants.VISIT_ACCOUNT_MANAGEMENT}); + } + + _jiG.i423(); + switchToLoading(); + } + } + + public static void handleLoginFailed(@MagicConstant(valuesFromClass = LoginResult.class) int var0, String var1) { + loggingIn = false; + if (_jiG != null && _jiG.isAlive) { + if (var0 == LoginResult.R8) { + var0 = LoginResult.R2; + if (_nlb) { + var1 = StringConstants.INVALID_PASS; + } else { + var1 = StringConstants.INVALID_USER_OR_PASS; + } + LoginForm._noe.a984(enteredUsername); + } + + boolean var2 = true; + if (var0 == LoginResult.R10) { + var2 = false; + f150mm(); + } + if (var2) { + if (_nsbD) { + var1 = StringConstants.PLEASE_TRY_AGAIN; + } + + _jiG.a503(var1, var0); + } + if (var0 != LoginResult.R256 && var0 != LoginResult.R10 && !_nlb) { + LoginForm._noe.l150(); + } + } + } + + private static void f150mm() { + if (_jiG != null) { + _jiG.i423(); + } + _sjb = new CreateDisplayNameForm(); + _aef.b952(_sjb); + } + + private static String a547lr(final CharSequence[] var0) { + return a176hm(var0, var0.length); + } + + private static String a176hm(final CharSequence[] var0, final int var2) { + if (var2 == 0) { + return ""; + } else if (var2 == 1) { + final CharSequence var3 = var0[0]; + return var3 != null ? var3.toString() : "null"; + } else { + int var4 = 0; + + for (int var5 = 0; var5 < var2; ++var5) { + final CharSequence var6 = var0[var5]; + if (var6 == null) { + var4 += 4; + } else { + var4 += var6.length(); + } + } + + final StringBuilder var9 = new StringBuilder(var4); + + for (int var10 = 0; var10 < var2; ++var10) { + final CharSequence var7 = var0[var10]; + if (var7 == null) { + var9.append("null"); + } else { + var9.append(var7); + } + } + + return var9.toString(); + } + } + + public static void a423oo() { + switchToLoading(); + _crb = TickResult.R4; + } + + private static void switchToLoading() { + root.startTransitioningOut(); + if (loadingBar == null) { + loadingBar = new LoadingBar(root, loadingNotificationMessage); + } + root.pushChild(loadingBar); + } + + public static void draw() { + root.drawRoot(0, 0); + } + + public static void drawLoading() { + if (loadingBar == null) { + loadingBar = new LoadingBar(root, loadingNotificationMessage); + root.pushChild(loadingBar); + } + loadingBar.update(loadingMessage, loadingPercent, loadingFailed); + Drawing.clear(); + draw(); + } + + public static void setLoadProgress(final float percent, final String message) { + loadingPercent = percent; + loadingMessage = message; + } + + public static void b423ol() { + _aef.b952(new JustPlayForm()); + } + + public enum TickResult { + R1, + R2, + LOGGING_IN, + R4, + TO_SERVER_LIST, + PLAY_FREE_VERSION, + TO_CUSTOMER_SUPPORT, + VIEW_MESSAGES, + RELOAD, + R12, + TO_LANGUAGE_SELECT, + RETURN_TO_GAME, + QUIT_TO_WEBSITE, + } + + @SuppressWarnings("WeakerAccess") + public static final class LoginResult { + public static final int NONE = -1; + public static final int SUCCESS = 0; + public static final int R1 = 1; + public static final int R2 = 2; + public static final int R3 = 3; + public static final int R5 = 5; + public static final int R8 = 8; + public static final int R10 = 10; + public static final int R256 = 256; + } +} diff --git a/src/main/java/funorb/commonui/Component.java b/src/main/java/funorb/commonui/Component.java new file mode 100644 index 0000000..1b785cf --- /dev/null +++ b/src/main/java/funorb/commonui/Component.java @@ -0,0 +1,229 @@ +package funorb.commonui; + +import funorb.awt.KeyState; +import funorb.awt.MouseState; +import funorb.commonui.listener.ComponentListener; +import funorb.commonui.renderer.ComponentRenderer; +import funorb.commonui.renderer.ITextRenderer; +import funorb.graphics.Sprite; +import funorb.shatteredplans.client.JagexApplet; +import org.intellij.lang.annotations.MagicConstant; + +import java.util.Arrays; +import java.util.Hashtable; + +public class Component { + private static int mouseButtonDown = 0; + + public TextLayout textLayout; + public ComponentListener listener; + public String tooltip; + public int width; + public int height; + public int x; + public int y; + public ComponentRenderer renderer; + protected int _o; + public String text; + public int _l = 0; + public int _h = 0; + public boolean isMouseOver; + + protected Component() { + } + + public Component(final String text, final ComponentRenderer renderer, final ComponentListener listener) { + this.text = text; + this.renderer = renderer; + this.listener = listener; + this.pack(); + } + + public final void pack() { + if (this.renderer instanceof ITextRenderer textRenderer) { + this.width = textRenderer.getPreferredWidth(this); + this.height = textRenderer.getPreferredHeight(this); + } + } + + protected Component(final int x, final int y, final int width, final int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public static Sprite createSolidSquareSprite(final int size, final int color) { + final Sprite var2 = new Sprite(size, size); + Arrays.fill(var2.pixels, color); + return var2; + } + + public final void d423() { + this.setBounds(this.x, this.y, this.width, this.height); + } + + public final void tickRoot(final int x, final int y, final boolean var2) { + this.tick(x, y, this); + final boolean var5 = this.isFocused(); + if (var2) { + if (JagexApplet.mouseWheelRotation != 0 && var5) { + this.a931(JagexApplet.mouseY, JagexApplet.mouseX, this, y, x, JagexApplet.mouseWheelRotation); + } + + if (JagexApplet.mouseButtonJustClicked != MouseState.Button.NONE) { + if (!this.a446(JagexApplet.mouseButtonJustClicked, JagexApplet.mousePressX, JagexApplet.mousePressY, x, y, this) && var5) { + this.unfocus(); + } + } + + if (JagexApplet.mouseButtonDown == MouseState.Button.NONE && mouseButtonDown != 0) { + this.a132(JagexApplet.mouseX, y, x, JagexApplet.mouseY, this); + } + } else if (var5 && JagexApplet.mouseButtonJustClicked != MouseState.Button.NONE) { + this.unfocus(); + } + + mouseButtonDown = JagexApplet.mouseButtonDown; + final String tooltip = this.getCurrentTooltip(); + if (TooltipManager.INSTANCE != null) { + TooltipManager.INSTANCE.tick(tooltip); + } + } + + /** + * @param previouslyFocused the component that previously had focus + * @return {@code true} if focus was successfully transferred, {@code false} otherwise + */ + public boolean focus(final Component previouslyFocused) { + return false; + } + + public void a132(final int var1, final int var2, final int var3, final int var4, final Component var6) { + this._o = 0; + } + + public void unfocus() { + } + + public final void keyTyped(final int keyCode, final char keyChar) { + if (!this.isFocused() || !this.a686(keyCode, keyChar, this)) { + if (keyCode == KeyState.Code.TAB) { + this.focus(this); + } + } + } + + public void draw(final int x, final int y) { + if (this.renderer != null) { + this.renderer.draw(this, x, y, true); + } + } + + public boolean a446(final int var1, final int var2, final int var4, final int var5, final int var6, final Component var7) { + if (this.a046(var2, var4, var6, var5)) { + this._o = var1; + } + return false; + } + + public void tick(final int x, final int y, final Component root) { + final boolean var5 = this.a046(JagexApplet.mouseX, JagexApplet.mouseY, y, x); + if (!this.isMouseOver == var5) { + this.isMouseOver = var5; + } + } + + protected final boolean a046(final int var1, final int var3, final int var4, final int var5) { + return this.x + var5 <= var1 && var3 >= var4 + this.y && var1 < this.width + this.x + var5 && var4 + this.y + this.height > var3; + } + + public void setBounds(final int x, final int y, final int width, final int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + if (this.textLayout != null) { + this.textLayout.invalidate(); + } + } + + public boolean a931(final int var2, final int var3, final Component var4, final int var5, final int var6, final int var7) { + return false; + } + + public final void drawRoot(final int x, final int y) { + this.draw(x, y); + TooltipManager.INSTANCE.maybeDrawTooltip(); + } + + public String getCurrentTooltip() { + return this.isMouseOver ? this.tooltip : null; + } + + public boolean isFocused() { + return false; + } + + public boolean a686(@MagicConstant(valuesFromClass = KeyState.Code.class) final int keyCode, final char keyChar, final Component var4) { + return false; + } + + @Override + public final String toString() { + return this.buildDebugString(new Hashtable<>(), 0, new StringBuilder()).toString(); + } + + public StringBuilder buildDebugString(final Hashtable cycles, final int nestingLevel, final StringBuilder builder) { + if (this.debugStringCycleCheck(cycles, builder)) { + this.putDefaultDebugString(cycles, nestingLevel, builder); + } + return builder; + } + + protected final boolean debugStringCycleCheck(final Hashtable cycles, final StringBuilder builder) { + if (cycles.containsKey(this)) { + builder.append(""); + return false; + } else { + cycles.put(this, this); + return true; + } + } + + protected final void putDefaultDebugString(final Hashtable cycles, final int nestingLevel, StringBuilder builder) { + builder.append(this.getClass().getName()) + .append("[0x").append(Integer.toHexString(this.hashCode())).append("] @") + .append(this.x).append(",").append(this.y).append(" ") + .append(this.width).append("x").append(this.height); + if (this.text != null) { + builder.append(" text=\"").append(this.text).append('"'); + } + + if (this.isMouseOver) { + builder.append(" mouseover"); + } + + if (this.isFocused()) { + builder.append(" focused"); + } + + if (this.renderer != null) { + builder.append(" renderer="); + if (this.renderer instanceof Component) { + builder = this.buildDebugString(cycles, nestingLevel + 1, builder); + } else { + builder.append(this.renderer); + } + } + + if (this.listener != null) { + builder.append(" listener="); + if (this.listener instanceof Component) { + this.buildDebugString(cycles, nestingLevel + 1, builder); + } else { + builder.append(this.listener); + } + } + } +} diff --git a/src/main/java/funorb/commonui/CreateAccountPage.java b/src/main/java/funorb/commonui/CreateAccountPage.java new file mode 100644 index 0000000..745c1a1 --- /dev/null +++ b/src/main/java/funorb/commonui/CreateAccountPage.java @@ -0,0 +1,123 @@ +package funorb.commonui; + +import funorb.commonui.form.CreateAccountForm; +import funorb.shatteredplans.client.JagexApplet; +import funorb.shatteredplans.StringConstants; + +import java.util.Objects; + +public final class CreateAccountPage extends AccountPage { + private final CreateAccountForm _Db; + private boolean _Eb; + private boolean _Hb; + + public CreateAccountPage(final NavigationRoot var1, final CreateAccountForm var2) { + super(var1, Resources.AREZZO_14_BOLD, StringConstants.CREATING_YOUR_ACCOUNT, false, false); + this._Db = var2; + } + + public static kj_ a431ck(final String var0, final int var1) { + final kj_ var3 = new kj_(false); + var3._c = var1; + var3._g = var0; + return var3; + } + + public static void b150rm() { + a584ai(JagexApplet._aeg, CreateAccountForm._G, true); + CommonUI._nsbD = true; + } + + private static kj_ a752br() { + if (CommonUI._eel == Enum1.C1) { + throw new IllegalStateException(); + } else if (CommonUI._eel == Enum1.C2) { + CommonUI._eel = Enum1.C1; + return JagexApplet._tplc; + } else { + return null; + } + } + + public static void a584ai(final String username, final String password, final boolean var0) { + CommonUI.enteredUsername = username; + CommonUI.enteredPassword = password; + CommonUI.setStateLoggingIn(StringConstants.LOGGING_IN, var0); + } + + @Override + public void handleButtonClicked(final Button button) { + if (this._Eb) { + CommonUI.switchToLogin(false, true); + } else { + b150rm(); + this.i423(); + } + } + + @Override + public void tick2() { + if (this.isAlive && !this._Hb) { + final kj_ var2 = a752br(); + if (var2 != null) { + this.a122(false, var2); + } + } + + super.tick2(); + } + + private void a122(final boolean var2, final kj_ var3) { + this._Hb = true; + String var4; + if (var3._h) { + var4 = StringConstants.ACCOUNT_CREATED_SUCCESSFULLY; + } else if (var3._d == null) { + var4 = var3._g; + if (var3._c == 248) { + if (!var2) { + CreateAccountForm.accountCreationFailed(); + } + + var4 = StringConstants.CREATE_INELIGIBLE; + this._Eb = true; + } + } else { + var4 = StringConstants.CREATE_USERNAME_UNAVAILABLE; + if (this._Db != null) { + this._Db.a150(); + } + } + + final cf_ var5 = new cf_(this, Resources.AREZZO_14_BOLD, var4); + if (var3._h) { + if (var3._b) { + this.b952(new pe_(this)); + return; + } + + var5.a700(this, StringConstants.CONT); + } else { + if (this._Eb) { + var5.a700(this, StringConstants.CONT); + } else if (var3._c == 5) { + var5.a966(StringConstants.RELOAD_GAME, CommonUI.TickResult.RELOAD); + var5.a966(StringConstants.QUIT_TO_WEBSITE, CommonUI.TickResult.QUIT_TO_WEBSITE); + } else { + var5.a966(StringConstants.BACK, null); + } + + if (var3._c == 3) { + var5.a966(StringConstants.TO_SERVER_LIST, CommonUI.TickResult.TO_SERVER_LIST); + } else if (var3._c == 6) { + var5.a966(StringConstants.TO_CUSTOMER_SUPPORT, CommonUI.TickResult.TO_CUSTOMER_SUPPORT); + } + } + + this.b952(var5); + } + + public void f487() { + this.a122(true, Objects.requireNonNull(a431ck(StringConstants.CREATE_INELIGIBLE, 248))); + } +} diff --git a/src/main/java/funorb/commonui/Enum1.java b/src/main/java/funorb/commonui/Enum1.java new file mode 100644 index 0000000..3d53407 --- /dev/null +++ b/src/main/java/funorb/commonui/Enum1.java @@ -0,0 +1,5 @@ +package funorb.commonui; + +public enum Enum1 { + C1, C2, C3 +} diff --git a/src/main/java/funorb/commonui/FormNavigationPage.java b/src/main/java/funorb/commonui/FormNavigationPage.java new file mode 100644 index 0000000..a2e5ab0 --- /dev/null +++ b/src/main/java/funorb/commonui/FormNavigationPage.java @@ -0,0 +1,129 @@ +package funorb.commonui; + +import funorb.awt.KeyState; + +public class FormNavigationPage extends FramedNavigationPage { + private final int _jb; + private final int _db; + private final int _mb; + private final int _X; + private Enum4 _ab; + private Component _ib; + private int _Z; + private cg_ _eb; + + protected FormNavigationPage(final NavigationRoot var1, final Component var2, final int var3, final int var4, final int var5) { + super(var1, 12 + var2.width, var2.height + var3 + 12); + this._db = var3; + this._mb = var5; + this._X = this._jb = var4; + this.a876(var2); + } + + private void a876(final Component var2) { + if (this._eb != null) { + this.removeChild(this._eb); + } + + if (var2 == null) { + this._eb = new cg_(); + } else { + var2.setBounds(6, 6 + this._db, var2.width, var2.height); + this._eb = new cg_(var2); + } + + this.addChild(this._eb); + this._ib = null; + } + + @Override + public boolean a686(final int keyCode, final char keyChar, final Component var4) { + if (super.a686(keyCode, keyChar, var4)) { + return true; + } else { + if (this._eb != null) { + if (keyCode == KeyState.Code.UP) { + this._eb.focus(var4); + } + + if (keyCode == KeyState.Code.DOWN) { + this._eb.focus(var4); + } + } + + return false; + } + } + + @Override + public final void g423() { + if (this._ab != Enum4.C2) { + this._Z = 0; + this._ab = Enum4.C3; + this.a876(this._ib); + this._eb._J = 0; + this._ib = null; + } + } + + @Override + public void tick2() { + if (this._ab != null) { + if (this._ab == Enum4.C2) { + if (this._X == ++this._Z) { + this._ab = Enum4.C1; + this.b115(this._mb, 12 + this._ib.width, this._ib.height + this._db + 12); + this._Z = 0; + this._eb._J = 0; + } else { + this._eb._J = -((this._Z << 8) / this._X) + 256; + } + } else if (this._ab == Enum4.C3) { + if (++this._Z == this._jb) { + this._eb._J = 256; + this._ab = null; + } else { + this._eb._J = (this._Z << 8) / this._jb; + } + } + } + + super.tick2(); + } + + public final void b952(final Component var1) { + this._ib = var1; + if (this._ab == Enum4.C1) { + this.b115(this._mb, this._ib.width + 12, this._ib.height + this._db + 12); + this._Z = 0; + } else if (this._ab != Enum4.C2) { + this._ab = Enum4.C2; + this._Z = 0; + } + } + + @Override + protected final void n150() { + if (this._ab != null) { + if (this._ab != Enum4.C3) { + this.b599(12 + this._db + this._ib.height, 12 + this._ib.width); + this.a876(this._ib); + } + + this._eb._J = 256; + this._ab = null; + } + + super.n150(); + } + + @Override + public final boolean k154() { + this.n150(); + return super.k154(); + } + + private enum Enum4 { + C1, C2, C3 + } +} diff --git a/src/main/java/funorb/commonui/FramedNavigationPage.java b/src/main/java/funorb/commonui/FramedNavigationPage.java new file mode 100644 index 0000000..3109cce --- /dev/null +++ b/src/main/java/funorb/commonui/FramedNavigationPage.java @@ -0,0 +1,177 @@ +package funorb.commonui; + +import funorb.graphics.Drawing; +import funorb.graphics.Sprite; + +public abstract class FramedNavigationPage extends NavigationPage { + private int _L; + private int _K; + private int _T; + private int _R; + private int _P = 0; + private int _Q = 0; + + protected FramedNavigationPage(final NavigationRoot root, final int width, final int height) { + super(root, width, height); + } + + private static void drawFrameTopBottom(final Sprite[] sprite, final int x, final int y, final int width) { + if (sprite != null && width > 0) { + final int leftOffset = sprite[0].offsetX; + final int middleOffset = sprite[1].offsetX; + final int rightOffset = sprite[2].offsetX; + sprite[0].draw(x, y); + sprite[2].draw(x + width - rightOffset, y); + Drawing.withSavedBounds(() -> { + Drawing.expandBoundsToInclude(leftOffset + x, y, x + width - rightOffset, sprite[1].offsetY + y); + final int right = x + width - rightOffset; + for (int i = x + leftOffset; i < right; i += middleOffset) { + sprite[1].draw(i, y); + } + }); + } + } + + protected final void b115(final int var2, final int var3, final int var4) { + if (var2 <= 0) { + this.b599(var4, var3); + } else { + this._L = this.width; + this._R = this.height; + this._T = var3; + this._Q = 0; + this._K = var4; + this._P = var2; + } + } + + @Override + protected void drawContent(final int x, final int y) { + Drawing.fillRectangleVerticalGradient(x + 6, y + 35, this.width - 12, this.height - 40, 0x202020, 0); + final byte var4 = 35; + final short var5 = 211; + int var7 = 0; + + int var8; + int var9; + for (var8 = y; var7 < var4; ++var8) { + if (Drawing.top <= var8 && var8 < Drawing.bottom) { + var9 = var5 + var7 * (-17) / var4; + int var10 = 0; + int var11 = this.width; + int var12; + int var13; + if (var7 <= 20) { + for (; var10 <= 20; ++var10) { + var12 = (-var7 + 20) * (-var7 + 20) + (20 - var10) * (-var10 + 20); + if (var12 <= 462) { + if (var12 < 420) { + break; + } + + var13 = (-var12 + 462) * var9 / 42; + var13 |= var13 << 16 | var13 << 8; + Drawing.screenBuffer[var10 + var8 * Drawing.width + x] = var13; + } + } + } + + if (var7 <= 20) { + var12 = var11; + var11 -= 21; + + for (var13 = 0; var13 <= 20; ++var11) { + final int var14 = var13 * var13 + (20 - var7) * (-var7 + 20); + if (var14 > 462) { + break; + } + + if (var14 >= 420) { + int var15 = var9 * (462 - var14) / 42; + var15 |= var15 << 8 | var15 << 16; + Drawing.screenBuffer[var11 + x + Drawing.width * var8] = var15; + } else { + var12 = var11 + 1; + } + + ++var13; + } + + var11 = var12; + } + + var9 |= var9 << 8 | var9 << 16; + Drawing.horizontalLine(var10 + x, var8, var11 - var10, var9); + } + + ++var7; + } + + final byte b = 22; + final short i1 = 194; + int i2 = 0; + + for (var8 = y + 35; i2 < b; ++var8) { + var9 = i1 + (-25) * i2 / b; + var9 |= var9 << 8 | var9 << 16; + Drawing.horizontalLine(x, var8, 6, var9); + Drawing.horizontalLine(this.width + x - 6, var8, 6, var9); + ++i2; + } + + Resources.JAGEX_LOGO_GREY.draw(this.width + x - 90, 10 + y); + drawFrameTopBottom(Resources.FRAME_TOP, 5 + x, y + 35, this.width - 10); + drawFrameTopBottom(Resources.FRAME_BOTTOM, x, this.height + y - 22, this.width); + final short i3 = 169; + final int var16 = this.height - 79; + int i4 = 0; + + for (var8 = y + 57; i4 < var16; ++var8) { + var9 = i3 + i4 * (-42) / var16; + var9 |= var9 << 16 | var9 << 8; + Drawing.horizontalLine(x, var8, 6, var9); + Drawing.horizontalLine(x + this.width - 6, var8, 6, var9); + ++i4; + } + + } + + protected void g423() { + } + + @Override + public boolean k154() { + this.n150(); + return super.k154(); + } + + protected void n150() { + if (this._P > 0) { + this.b599(this._K, this._T); + this._P = 0; + this.g423(); + } + } + + @Override + public void tick2() { + int var2; + if (this._P > 0) { + var2 = this._T; + int var3 = this._K; + if (++this._Q >= this._P) { + this._P = 0; + this.g423(); + } else { + final int var4 = (-this._Q + 2 * this._P) * this._Q; + final int var5 = this._P * this._P; + var3 = var4 * (-this._R + this._K) / var5 + this._R; + var2 = (this._T - this._L) * var4 / var5 + this._L; + } + + this.b599(var3, var2); + } + + super.tick2(); + } +} diff --git a/src/main/java/funorb/commonui/LoadingBar.java b/src/main/java/funorb/commonui/LoadingBar.java new file mode 100644 index 0000000..3b4eb8f --- /dev/null +++ b/src/main/java/funorb/commonui/LoadingBar.java @@ -0,0 +1,60 @@ +package funorb.commonui; + +import funorb.graphics.Drawing; +import funorb.graphics.Font; + +public final class LoadingBar extends FramedNavigationPage { + private String progressMessage; + private final String notificationMessage; + private final ProgressBar progressBar; + private boolean failed; + private boolean animationDisabled; + + public LoadingBar(final NavigationRoot root, final String notificationMessage) { + super(root, 300, 120); + this.notificationMessage = notificationMessage; + if (this.notificationMessage != null) { + final int var3 = Resources.AREZZO_14_BOLD.measureParagraphHeight(this.notificationMessage, 260, Resources.AREZZO_14_BOLD.ascent); + this.b599(150 + var3, 300); + } + + this.progressBar = new ProgressBar(); + this.progressBar.animateStripes = true; + this.animationDisabled = false; + this.failed = false; + this.addChild(this.progressBar); + } + + public void disableAnimation() { + this.animationDisabled = true; + this.progressBar.animateStripes = false; + } + + @Override + public void drawContent(final int x, final int y) { + super.drawContent(x, y); + Resources.AREZZO_14_BOLD.drawCentered(this.progressMessage, (this.width / 2) + x, 103 + y, Drawing.WHITE); + if (this.notificationMessage != null) { + Drawing.horizontalLine(x + 20, y + 113, 260, 0x808080); + Resources.AREZZO_14_BOLD.drawParagraph(this.notificationMessage, x + 20, y + 128, 260, 100, Drawing.WHITE, Font.HorizontalAlignment.CENTER, Font.VerticalAlignment.TOP, Resources.AREZZO_14_BOLD.ascent); + } + } + + public void update(final String message, final float percent, final boolean failed) { + if (this.failed == !failed) { + this.failed = failed; + if (this.failed) { + this.progressBar.setColor(ProgressBar.FAILURE_COLOR); + this.progressBar.animateStripes = true; + } else { + this.progressBar.setColor(ProgressBar.LOADING_COLOR); + if (this.animationDisabled) { + this.progressBar.animateStripes = false; + } + } + } + + this.progressMessage = message; + this.progressBar.progress = (int) (percent / 100.0F * (float) ProgressBar.MAX_PROGRESS); + } +} diff --git a/src/main/java/funorb/commonui/NavigationPage.java b/src/main/java/funorb/commonui/NavigationPage.java new file mode 100644 index 0000000..de82b70 --- /dev/null +++ b/src/main/java/funorb/commonui/NavigationPage.java @@ -0,0 +1,85 @@ +package funorb.commonui; + +import funorb.commonui.container.ListContainer; +import funorb.graphics.Drawing; +import funorb.graphics.Sprite; +import funorb.shatteredplans.client.ShatteredPlansClient; +import org.jetbrains.annotations.NotNull; + +public abstract class NavigationPage extends ListContainer { + private static Sprite drawBuffer; + + private final NavigationRoot root; + public boolean isAlive = false; + private int alpha; + + protected NavigationPage(final NavigationRoot root, final int width, final int height) { + super((ShatteredPlansClient.SCREEN_WIDTH - width) / 2, (ShatteredPlansClient.SCREEN_HEIGHT - height) / 2, width, height); + this.root = root; + this.alpha = 0; + } + + @Override + public final void draw(final int x, final int y) { + if (this.alpha != 0) { + if (this.alpha >= 256) { + this.drawContent(this.x + x, this.y + y); + super.draw(x, y); + } else { + if (drawBuffer == null || drawBuffer.width < this.width || drawBuffer.height < this.height) { + drawBuffer = new Sprite(this.width, this.height); + } + + drawBuffer.withInstalledForDrawingUsingOffsets(() -> { + Drawing.clear(); + this.drawContent(0, 0); + super.draw(-x - this.x, -y - this.y); + }); + drawBuffer.draw(this.x + x, this.y + y, this.alpha); + } + } + } + + public boolean k154() { + this.alpha = this.getTargetAlpha(); + if (this.isAlive) { + return false; + } else { + assert this.alpha == 0; + return true; + } + } + + @Override + public final @NotNull Component getFocusedChild() { + final Component child = super.getFocusedChild(); + return child != null ? child : this; + } + + public void tick2() { + final int targetAlpha = this.getTargetAlpha(); + final int diff = targetAlpha - this.alpha; + if (diff > 0) { // fading in + this.alpha += ((diff - 1) + 8) / 8; + } + if (diff < 0) { // fading out + this.alpha += ((diff - 16) + 1) / 16; + } + } + + public final boolean isReadyToBeRemoved() { + return this.alpha == 0 && this.getTargetAlpha() == 0 && !this.isAlive; + } + + protected final void b599(final int var1, final int var2) { + this.setBounds(ShatteredPlansClient.SCREEN_WIDTH - var2 >> 1, ShatteredPlansClient.SCREEN_HEIGHT - var1 >> 1, var2, var1); + } + + private int getTargetAlpha() { + return !this.isAlive ? 0 + : this == this.root.getActive() ? 256 + : 0; + } + + protected abstract void drawContent(int x, int y); +} diff --git a/src/main/java/funorb/commonui/NavigationRoot.java b/src/main/java/funorb/commonui/NavigationRoot.java new file mode 100644 index 0000000..002b96a --- /dev/null +++ b/src/main/java/funorb/commonui/NavigationRoot.java @@ -0,0 +1,68 @@ +package funorb.commonui; + +import funorb.commonui.container.WrapperContainer; +import funorb.shatteredplans.client.ShatteredPlansClient; +import org.jetbrains.annotations.Contract; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Iterator; + +public final class NavigationRoot extends WrapperContainer { + private final Deque children = new ArrayDeque<>(); + + public NavigationRoot() { + super(0, 0, ShatteredPlansClient.SCREEN_WIDTH, ShatteredPlansClient.SCREEN_HEIGHT); + } + + public void startTransitioningOut() { + for (final NavigationPage child : this.children) { + child.isAlive = false; + } + this.child = null; + } + + public void tick2() { + for (final Iterator it = this.children.iterator(); it.hasNext();) { + final NavigationPage child = it.next(); + child.tick2(); + if (child.isReadyToBeRemoved()) { + it.remove(); + } + } + this.child = this.getActive(); + } + + @Contract(pure = true) + public NavigationPage getActive() { + return this.children.stream().filter(var3 -> var3.isAlive).findFirst().orElse(null); + } + + @Override + public void draw(final int x, final int y) { + if (this.renderer != null) { + this.renderer.draw(this, x, y, true); + } + + for (final Iterator it = this.children.descendingIterator(); it.hasNext();) { + final NavigationPage child = it.next(); + child.draw(x + this.x, this.y + y); + } + } + + public void pushChild(final NavigationPage child) { + this.children.push(child); + child.isAlive = true; + child.focus(this); + } + + public void switchToLoadingScreen() { + this.children.removeIf(NavigationPage::k154); + } + + @Override + public Component a274() { + return this.children.stream().filter(var3 -> var3.isAlive) + .findFirst().map(NavigationPage::getFocusedChild).orElse(null); + } +} diff --git a/src/main/java/funorb/commonui/ProgressBar.java b/src/main/java/funorb/commonui/ProgressBar.java new file mode 100644 index 0000000..b577786 --- /dev/null +++ b/src/main/java/funorb/commonui/ProgressBar.java @@ -0,0 +1,150 @@ +package funorb.commonui; + +import funorb.graphics.Drawing; +import funorb.graphics.Sprite; + +public final class ProgressBar extends Component { + public static final int MAX_PROGRESS = 65536; + private final int STRIPE_WIDTH = 15; + + public static final int LOADING_COLOR = 0x204060; + public static final int SUCCESS_COLOR = 0x206040; + public static final int FAILURE_COLOR = 0x804020; + + private static final int EMPTY_BASE_COLOR = 0x202020; + private static final int FILLED_BASE_COLOR = 0x404040; + + private int emptyAccentColor = 0x102030; + private int filledAccentColor = 0x204060; + + public boolean animateStripes; + public int progress; + private Sprite _S; + private Sprite _R; + private int stripeOffset; + private Sprite _N; + private Sprite[] _z; + + public ProgressBar() { + this.setBounds(13, 50, 274, 30); + } + + private Sprite a119(final int color1, final int color2) { + final Sprite sprite = new Sprite(this.STRIPE_WIDTH * 2, this.height); + sprite.withInstalledForDrawingUsingOffsets(() -> { + final int halfHeight = this.height / 2; + for (int i = 0; i < this.height; ++i) { + final int var8 = (((this.STRIPE_WIDTH * 2) - 1) * (i / 2)) % (2 * this.STRIPE_WIDTH); + final int var9 = color1 & 0xff00ff; + final int var10 = color1 & 0x00ff00; + final int var11 = i - halfHeight; + final int var12 = 128 + (int) (Math.sqrt((halfHeight * halfHeight) - (var11 * var11)) / (double) halfHeight * 128.0D); + final int var13 = var12 >= 256 ? var9 | var10 : (var12 * var10 & 16711680 | -16711936 & var12 * var9) >>> 8; + Drawing.horizontalLine(var8, i, this.STRIPE_WIDTH, var13); + Drawing.horizontalLine(var8 - this.STRIPE_WIDTH * 2, i, this.STRIPE_WIDTH, var13); + final int i3 = '\uff00' & color2; + final int i1 = 16711935 & color2; + final int i2 = (var12 >= 256) ? (i3 | i1) : (((0xff0000 & (var12 * i3)) | ((i1 * var12) & 0xff00ff00)) >>> 8); + Drawing.horizontalLine(var8 + this.STRIPE_WIDTH, i, this.STRIPE_WIDTH, i2); + Drawing.horizontalLine(-this.STRIPE_WIDTH + var8, i, this.STRIPE_WIDTH, i2); + } + }); + return sprite; + } + + private void buildSprites() { + this._z = new Sprite[]{this.a119(this.filledAccentColor, FILLED_BASE_COLOR), this.a119(this.emptyAccentColor, EMPTY_BASE_COLOR)}; + this._R = this.h432(); + this._N = this._R.horizontallyFlipped(); + this._S = new Sprite(this.height / 2, this.height); + } + + @Override + public void setBounds(final int x, final int y, final int width, final int height) { + super.setBounds(x, y, width, height); + this.buildSprites(); + } + + private void a854(final Sprite var1, final int var2, final int var3) { + final int var5 = var3 + this.width; + Drawing.withLocalContext(() -> { + Drawing.expandBoundsToInclude(var3 + this._R.width, var2, var5 - this._R.width, this.height + var2); + for (int var6 = -this.stripeOffset + var3; var5 > var6; var6 += var1.width) { + var1.draw(var6, var2); + } + }); + + if (Drawing.left <= var3 + this._R.width) { + this._S.withInstalledForDrawingUsingOffsets(() -> { + var1.draw(-this.stripeOffset, 0); + var1.draw(-this.stripeOffset + this.STRIPE_WIDTH * 2, 0); + this._N.e093(); + }); + this._S.draw(var3, var2); + } + + if (Drawing.right >= -this._R.width + var5) { + this._S.withInstalledForDrawingUsingOffsets(() -> { + int var7 = -this._R.width + this.width + this.stripeOffset; + while (2 * this.STRIPE_WIDTH < var7) { + var7 -= 2 * this.STRIPE_WIDTH; + } + + var1.draw(-var7, 0); + var1.draw(this.STRIPE_WIDTH * 2 - var7, 0); + this._R.e093(); + }); + this._S.draw(-this._R.width + var5, var2); + } + + } + + @Override + public void tick(final int x, final int y, final Component root) { + if (this.animateStripes) { + ++this.stripeOffset; + if (this.stripeOffset > this.STRIPE_WIDTH * 2) { + this.stripeOffset -= this.STRIPE_WIDTH * 2; + } + } + } + + @Override + public void draw(final int x, final int y) { + final int var5 = x + this.x; + final int var6 = this.y + y; + this.a854(this._z[0], var6, var5); + if (this.progress < MAX_PROGRESS) { + Drawing.withLocalContext(() -> { + Drawing.expandBoundsToInclude(var5 + (this.progress * this.width >> 16), var6, var5 + this.width, var6 + this.height); + this.a854(this._z[1], var6, var5); + }); + } + } + + private Sprite h432() { + final int width = this.height / 2; + final Sprite sprite = new Sprite(width, this.height); + sprite.withInstalledForDrawingUsingOffsets(() -> { + for (int y = 0; y < this.height; ++y) { + for (int x = 0; x < width; ++x) { + double var7 = ((double) x * (double) x) / (double) (y * (this.height - y)); + int gray = 1; + if (var7 < 1.0D) { + var7 = Math.sqrt(1.0D - var7); + gray = var7 < 1.0D ? (int) (255.0D * var7) : 255; + } + + Drawing.setPixel(x, y, Drawing.gray(gray)); + } + } + }); + return sprite; + } + + public void setColor(final int color) { + this.emptyAccentColor = (color >> 1) & 0x7f7f7f; + this.filledAccentColor = color; + this.buildSprites(); + } +} diff --git a/src/main/java/funorb/commonui/Resources.java b/src/main/java/funorb/commonui/Resources.java new file mode 100644 index 0000000..f02e9b4 --- /dev/null +++ b/src/main/java/funorb/commonui/Resources.java @@ -0,0 +1,87 @@ +package funorb.commonui; + +import funorb.cache.ResourceLoader; +import funorb.client.JagexBaseApplet; +import funorb.commonui.renderer.ButtonRenderer; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.graphics.PalettedSymbol; +import funorb.graphics.Sprite; +import funorb.graphics.SpriteResource; + +public final class Resources { + public static Sprite[] FRAME_TOP; + public static Sprite[] FRAME_BOTTOM; + public static Sprite JAGEX_LOGO_GREY; + public static Sprite[] VALIDATION; + public static Font AREZZO_12; + public static Font AREZZO_14; + public static Font AREZZO_14_BOLD; + + public static void load(final ResourceLoader spritesLoader, final ResourceLoader fontsLoader, final ResourceLoader dataLoader) { + FRAME_TOP = SpriteResource.loadSprites(spritesLoader, "commonui", "frame_top"); + FRAME_BOTTOM = SpriteResource.loadSprites(spritesLoader, "commonui", "frame_bottom"); + JAGEX_LOGO_GREY = SpriteResource.loadSprite(spritesLoader, "commonui", "jagex_logo_grey"); + ButtonRenderer.SPRITES = SpriteResource.loadSprites(spritesLoader, "commonui", "button"); + VALIDATION = SpriteResource.loadSprites(spritesLoader, "commonui", "validation"); + + AREZZO_12 = SpriteResource.loadPalettedSpriteFont(spritesLoader, fontsLoader, "commonui", "arezzo12"); + AREZZO_14 = SpriteResource.loadPalettedSpriteFont(spritesLoader, fontsLoader, "commonui", "arezzo14"); + AREZZO_14_BOLD = SpriteResource.loadPalettedSpriteFont(spritesLoader, fontsLoader, "commonui", "arezzo14bold"); + + final Sprite buttonGif = new Sprite(dataLoader.getResource("button.gif", ""), JagexBaseApplet.canvas); + + final PalettedSymbol[] screenOptions = SpriteResource.loadPalettedSprites(spritesLoader, "commonui", "screen_options"); + final PalettedSymbol[][] var5 = new PalettedSymbol[][]{new PalettedSymbol[4], new PalettedSymbol[4], new PalettedSymbol[4]}; + final int[][] var6 = new int[4][]; + var6[0] = screenOptions[0].palette; + + for (int i = 1; i < var6.length; ++i) { + var6[i] = var6[0].clone(); + } + + final byte var12 = screenOptions[0].pixels[0]; + var6[1][var12] = 0x2488e6; + var6[2][var12] = Drawing.WHITE; + var6[3][var12] = 0x48c0ff; + + for (int i = 0; i < 3; ++i) { + final PalettedSymbol[] var9 = var5[i]; + for (int j = 0; j < var9.length; ++j) { + var9[j] = alternatePalette(screenOptions[i], var6[j]); + } + } + + Drawing.withLocalContext(() -> { + buttonGif.installForDrawing(); + Drawing.e115(Drawing.width, Drawing.height); + + final Sprite var13 = new Sprite(buttonGif.height, buttonGif.height); + var13.installForDrawing(); + buttonGif.c093(0, 0); + + final Sprite var14 = new Sprite(buttonGif.height, buttonGif.height); + var14.installForDrawing(); + buttonGif.c093(buttonGif.height - buttonGif.width, 0); + + final Sprite var11 = new Sprite(buttonGif.width - 2 * buttonGif.height, buttonGif.height); + var11.installForDrawing(); + buttonGif.c093(-buttonGif.height, 0); + + ButtonRenderer.SPRITES = new Sprite[]{var13, var11, var14}; + }); + } + + private static PalettedSymbol alternatePalette(final PalettedSymbol symbol, final int[] palette) { + final PalettedSymbol newSymbol = new PalettedSymbol(); + newSymbol.height = symbol.height; + newSymbol.width = symbol.width; + newSymbol.palette = palette; + newSymbol.advanceY = symbol.advanceY; + newSymbol.y = symbol.y; + newSymbol.x = symbol.x; + newSymbol.pixels = symbol.pixels; + newSymbol.advanceX = symbol.advanceX; + return newSymbol; + } +} diff --git a/src/main/java/funorb/commonui/TextLayout.java b/src/main/java/funorb/commonui/TextLayout.java new file mode 100644 index 0000000..f86ed0d --- /dev/null +++ b/src/main/java/funorb/commonui/TextLayout.java @@ -0,0 +1,139 @@ +package funorb.commonui; + +import funorb.graphics.Font; +import org.jetbrains.annotations.NotNull; + +public final class TextLayout extends AbstractTextLayout { + private boolean needsRelayout = false; + private boolean isSingleLine; + private Font font; + private String text; + private @NotNull Font.HorizontalAlignment horizontalAlignment = Font.HorizontalAlignment.LEFT; + private @NotNull Font.VerticalAlignment verticalAlignment = Font.VerticalAlignment.TOP; + private int availableWidth; + private int availableHeight; + private int leading; + + public void invalidate() { + this.needsRelayout = true; + } + + public void layoutLineAlignedLeft(final Font font, final String text, final int baseline) { + if (text == null) { + this.lineMetrics = null; + } else if (this.needsRelayout || this.font != font || !this.isSingleLine || this.horizontalAlignment != Font.HorizontalAlignment.LEFT || this.text == null || !this.text.equals(text)) { + this.font = font; + this.text = text; + this.horizontalAlignment = Font.HorizontalAlignment.LEFT; + final TextLineMetrics var6 = this.initializeSingleLineLayout(font, text, baseline); + var6._b[0] = 0; + var6._b[text.length()] = font.measureLineWidth(text); + var6.a137ta(font, text, 0); + } + this.needsRelayout = false; + } + + public void layoutLineAlignedRight(final int var2, final Font font, final String text, final int var5) { + if (text == null) { + this.lineMetrics = null; + } else if (this.needsRelayout || font != this.font || !this.isSingleLine || this.horizontalAlignment != Font.HorizontalAlignment.RIGHT || this.text == null || !this.text.equals(text)) { + this.font = font; + this.horizontalAlignment = Font.HorizontalAlignment.RIGHT; + this.text = text; + final TextLineMetrics var6 = this.initializeSingleLineLayout(font, text, var2); + var6._b[0] = var5 - font.measureLineWidth(text); + var6._b[text.length()] = var5; + var6.a137ta(font, text, 0); + } + this.needsRelayout = false; + } + + public void layoutLineCentered(final int var1, final String text, final Font font, final int var5) { + if (text == null) { + this.lineMetrics = null; + } else if (this.needsRelayout || this.font != font || !this.isSingleLine || this.horizontalAlignment != Font.HorizontalAlignment.CENTER || this.text == null || !this.text.equals(text)) { + this.horizontalAlignment = Font.HorizontalAlignment.CENTER; + this.font = font; + final TextLineMetrics var6 = this.initializeSingleLineLayout(font, text, var1); + final int var7 = font.measureLineWidth(text); + var6._b[0] = var5 - (var7 / 2); + var6._b[text.length()] = var5 + (var7 >> 1); + var6.a137ta(font, text, 0); + } + this.needsRelayout = false; + } + + private TextLineMetrics initializeSingleLineLayout(final Font font, final String text, final int baseline) { + this.isSingleLine = true; + final TextLineMetrics var5 = new TextLineMetrics(baseline - font.ascent, baseline + font.descent, text.length()); + this.lineMetrics = new TextLineMetrics[]{var5}; + return var5; + } + + public void layoutParagraph(final Font font, + final String text, + final @NotNull Font.HorizontalAlignment horizontalAlignment, + final @NotNull Font.VerticalAlignment verticalAlignment, + final int availableWidth, + final int availableHeight, + int leading) { + if (leading == 0) { + leading = font.baseline; + } + + if (text == null) { + this.lineMetrics = null; + } else if (this.needsRelayout + || this.isSingleLine + || this.font != font + || this.horizontalAlignment != horizontalAlignment + || this.verticalAlignment != verticalAlignment + || this.leading != leading + || this.availableHeight != availableHeight + || this.availableWidth != availableWidth + || this.text == null || !this.text.equals(text)) { + this.isSingleLine = false; + this.font = font; + this.verticalAlignment = verticalAlignment; + this.availableWidth = availableWidth; + this.horizontalAlignment = horizontalAlignment; + this.text = text; + this.availableHeight = availableHeight; + this.leading = leading; + final String[] lines = new String[font.breakLines(text, availableWidth) + 1]; + final int lineCount = Math.max(1, font.breakLines(text, new int[]{availableWidth}, lines)); + if (this.verticalAlignment == Font.VerticalAlignment.DISTRIBUTE && lineCount == 1) { + this.verticalAlignment = Font.VerticalAlignment.MIDDLE; + } + + int baseline; + if (this.verticalAlignment == Font.VerticalAlignment.TOP) { + baseline = font.ascent; + } else if (this.verticalAlignment == Font.VerticalAlignment.MIDDLE) { + baseline = font.ascent + (this.availableHeight - lineCount * this.leading >> 1); + } else if (this.verticalAlignment == Font.VerticalAlignment.BOTTOM) { + baseline = this.availableHeight - font.descent - this.leading * lineCount; + } else { + final int var12 = Math.max((this.availableHeight - this.leading * lineCount) / (lineCount + 1), 0); + baseline = var12 + font.ascent; + this.leading += var12; + } + + this.lineMetrics = new TextLineMetrics[lineCount]; + for (int i = 0; i < lineCount; ++i) { + final String var13 = lines[i]; + final TextLineMetrics var14 = new TextLineMetrics(baseline - font.ascent, baseline + font.descent, var13 == null ? 0 : var13.length()); + var14._b[0] = 0; + if (var13 != null) { + var14._b[var13.length()] = font.measureLineWidth(var13); + var14.a137ta(font, var13, horizontalAlignment != Font.HorizontalAlignment.JUSTIFY ? 0 : this.a947(availableWidth, font.measureLineWidth(var13), var13)); + } + + this.lineMetrics[i] = var14; + baseline += leading; + } + } + + this.needsRelayout = false; + } +} diff --git a/src/main/java/funorb/commonui/TextLineMetrics.java b/src/main/java/funorb/commonui/TextLineMetrics.java new file mode 100644 index 0000000..84bdef2 --- /dev/null +++ b/src/main/java/funorb/commonui/TextLineMetrics.java @@ -0,0 +1,58 @@ +package funorb.commonui; + +import funorb.graphics.Font; + +public final class TextLineMetrics { + public final int top; + public final int bottom; + public final int[] _b; + + public TextLineMetrics(final int top, final int bottom, final int charCount) { + this.top = top; + this.bottom = bottom; + this._b = new int[charCount + 1]; + } + + public void a137ta(final Font font, final String text, final int spaceWidth) { + int totalSpaceWidth = 0; + int var6 = -1; + + for (int i = 1; i < text.length(); ++i) { + final char c = text.charAt(i); + if (c == '<') { + var6 = (totalSpaceWidth >> 8) + this._b[0] + font.measureLineWidth(text.substring(0, i)); + } + + if (var6 == -1) { + if (c == ' ') { + totalSpaceWidth += spaceWidth; + } + + this._b[i] = (totalSpaceWidth >> 8) - (font.getAdvanceWidth(c) - this._b[0] - font.measureLineWidth(text.substring(0, i + 1))); + } else { + this._b[i] = var6; + } + + if (c == '>') { + var6 = -1; + } + } + } + + public int getCharCount() { + return this._b.length - 1; + } + + public int a527(final int var2) { + for (int i = 1; i < this._b.length; ++i) { + if (var2 < this._b[i] + this._b[i - 1] >> 1) { + return i - 1; + } + } + return this.getCharCount(); + } + + public int getWidth() { + return this._b[this.getCharCount()]; + } +} diff --git a/src/main/java/funorb/commonui/TooltipManager.java b/src/main/java/funorb/commonui/TooltipManager.java new file mode 100644 index 0000000..5310099 --- /dev/null +++ b/src/main/java/funorb/commonui/TooltipManager.java @@ -0,0 +1,134 @@ +package funorb.commonui; + +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.shatteredplans.client.JagexApplet; + +import java.util.Arrays; + +public final class TooltipManager { + public static TooltipManager INSTANCE; + + public static void initialize(final Font font) { + if (INSTANCE == null) { + INSTANCE = new TooltipManager(font); + } + } + + private static final int SHOW_MIN_TICKS = 50; + private static final int SHOW_MAX_TICKS = 300; + + private static final int OUTLINE_COLOR = 0x757575; + private static final int BACKGROUND_COLOR = 0x2a2a2a; + private static final int TEXT_COLOR = 0xeeeeee; + private static final int PADDING_RIGHT = 5; + private static final int PADDING_LEFT = 6; + private static final int PADDING_TOP = 4; + private static final int LEADING = 14; + + private final Font font; + private final String[] tooltipLines = new String[16]; + + private int mouseX = -1; + private int mouseY = -1; + private int tooltipX = -1; + private int tooltipY = -1; + private int tooltipTimer = 0; + private boolean hideTooltip = false; + private String currentTooltip = null; + + private TooltipManager(final Font font) { + this.font = font; + } + + public void setMousePosition(final int x, final int y) { + this.mouseX = x; + this.mouseY = y; + } + + public void reset() { + this.currentTooltip = null; + this.hideTooltip = false; + this.tooltipY = -1; + this.tooltipX = -1; + this.tooltipTimer = 0; + } + + public void tick(final String tooltip) { + if (this.mouseX == -1 && this.mouseY == -1) { + this.setMousePosition(JagexApplet.mouseX, JagexApplet.mouseY); + } + + ++this.tooltipTimer; + if (this.currentTooltip == null) { + final boolean timeToShowTooltip = this.isTimeToShowTooltip(); + if (tooltip == null || (!this.hideTooltip && !timeToShowTooltip)) { + this.tooltipTimer = 0; + } else { + this.tooltipTimer = SHOW_MIN_TICKS; + } + if (tooltip != null) { + this.hideTooltip = false; + } else if (!this.hideTooltip && timeToShowTooltip) { + this.hideTooltip = true; + } + this.tooltipY = this.mouseY; + this.tooltipX = this.mouseX; + } + + this.currentTooltip = tooltip; + if (!this.hideTooltip && this.tooltipTimer < SHOW_MIN_TICKS && JagexApplet.mouseEventReceived) { + this.tooltipTimer = 0; + this.tooltipY = this.mouseY; + this.tooltipX = this.mouseX; + } + + this.setMousePosition(-1, -1); + if (this.hideTooltip && this.tooltipTimer == 10) { + this.hideTooltip = false; + this.tooltipTimer = 0; + } + } + + public void maybeDrawTooltip() { + final String tooltip = (!this.hideTooltip && this.isTimeToShowTooltip()) ? this.currentTooltip : null; + if (tooltip != null) { + this.drawTooltip(this.tooltipX, this.tooltipY, tooltip); + } + } + + private boolean isTimeToShowTooltip() { + return this.tooltipTimer >= SHOW_MIN_TICKS && this.tooltipTimer < SHOW_MAX_TICKS; + } + + private void drawTooltip(final int x, final int y, final String text) { + final int quarterWidth = Drawing.width / 4; + int textWidth = this.font.measureLineWidth(text); + int textHeight = this.font.ascent + this.font.descent; + if (quarterWidth < textWidth || text.contains("
")) { + + final int maxWidth; + if (textWidth > quarterWidth) { + final int var13 = textWidth / quarterWidth; + maxWidth = quarterWidth + 2 * ((var13 + textWidth % quarterWidth - 1) / var13); + } else { + maxWidth = quarterWidth; + } + + final int lineCount = this.font.breakLines(text, new int[]{maxWidth}, this.tooltipLines); + textHeight += LEADING * (lineCount - 1); + textWidth = Arrays.stream(this.tooltipLines).mapToInt(this.font::measureLineWidth).max().orElseThrow(); + } + + final int padding = PADDING_LEFT + PADDING_RIGHT; + final int x1 = Math.min(x, Drawing.width - padding - textWidth); + int y1 = y - this.font.capHeight + 32; + if (y1 > Drawing.height - textHeight - PADDING_TOP) { + y1 = y - textHeight - PADDING_TOP; + } + + Drawing.strokeRectangle(x1, y1, textWidth + padding, textHeight + PADDING_TOP, OUTLINE_COLOR); + Drawing.fillRect(x1 + 1, y1 + 1, textWidth + padding - 2, textHeight + PADDING_TOP - 2, BACKGROUND_COLOR); + this.font.drawParagraph(text, x1 + PADDING_LEFT, y1, textWidth, textHeight, TEXT_COLOR, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, LEADING); + } +} diff --git a/src/main/java/funorb/commonui/ah_.java b/src/main/java/funorb/commonui/ah_.java new file mode 100644 index 0000000..e4069b1 --- /dev/null +++ b/src/main/java/funorb/commonui/ah_.java @@ -0,0 +1,94 @@ +package funorb.commonui; + +import funorb.commonui.form.validator.InputValidator; +import funorb.commonui.form.validator.ValidationState; +import funorb.commonui.renderer.ITextRenderer; +import funorb.commonui.renderer.TextRenderer; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.graphics.Sprite; +import funorb.shatteredplans.StringConstants; + +public final class ah_ extends ts_ { + private static TextRenderer _qqo; + private final InputValidator _M; + private final String _W; + private Sprite _V; + private int _N; + + @SuppressWarnings("SameParameterValue") + public ah_(final InputValidator var1, final String var2, final int x, final int y, final int width, final int height) { + super(var2, b040ea()); + this._M = var1; + this._W = var2; + this.setBounds(x, y, width, height); + } + + private static TextRenderer b040ea() { + if (_qqo == null) { + _qqo = new TextRenderer(Resources.AREZZO_12, 20, 0, 0, 0, 0xb0b0b0, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, Resources.AREZZO_12.ascent, true); + } + + return _qqo; + } + + @Override + public void tick(final int x, final int y, final Component root) { + ++this._N; + super.tick(x, y, root); + } + + @Override + public void draw(final int x, final int y) { + final ValidationState var6 = this._M.validate(); + String var5; + if (var6 == ValidationState.CHECKING_2 || var6 == ValidationState.CHECKING_1) { + var5 = StringConstants.CHECKING; + } else { + var5 = this._M.a983(); + if (var5 == null) { + var5 = this._W; + } + } + + if (!var5.equals(this.text)) { + this.text = var5; + this.e487(); + } + + super.draw(x, y); + final ValidationState c226 = this._M.validate(); + final ITextRenderer var8 = (ITextRenderer) this.renderer; + final int var9 = this.x + x; + final int var10 = var8.a754(y, this) + (var8.updateLayout(this).b137() >> 1); + final Sprite var7; + if (c226 == ValidationState.CHECKING_2 || c226 == ValidationState.CHECKING_1) { + var7 = Resources.VALIDATION[0]; + final int var11 = var7.offsetX << 1; + final int var12 = var7.offsetY << 1; + if (this._V != null && this._V.width >= var11 && this._V.height >= var12) { + this._V.withInstalledForDrawingUsingOffsets(() -> { + Drawing.clear(); + var7.b669(112, 144, var7.offsetX << 4, var7.offsetY << 4, -this._N << 10, 4096); + }); + } else { + this._V = new Sprite(var11, var12); + this._V.withInstalledForDrawingUsingOffsets(() -> + var7.b669(112, 144, var7.offsetX << 4, var7.offsetY << 4, -this._N << 10, 4096)); + } + this._V.drawAdd(var9 - (var7.offsetX >> 1), -var7.offsetY + var10, 256); + } else if (c226 == ValidationState.INVALID) { + var7 = Resources.VALIDATION[2]; + var7.drawAdd(var9, var10 - (var7.height >> 1), 256); + } else if (c226 == ValidationState.C2) { + var7 = Resources.VALIDATION[1]; + var7.drawAdd(var9, -(var7.height >> 1) + var10, 256); + } + + } + + @Override + public String getCurrentTooltip() { + return null; + } +} diff --git a/src/main/java/funorb/commonui/cf_.java b/src/main/java/funorb/commonui/cf_.java new file mode 100644 index 0000000..cba78c8 --- /dev/null +++ b/src/main/java/funorb/commonui/cf_.java @@ -0,0 +1,79 @@ +package funorb.commonui; + +import funorb.commonui.container.ListContainer; +import funorb.commonui.listener.ButtonListener; +import funorb.commonui.listener.ComponentListener; +import funorb.graphics.Drawing; +import funorb.graphics.Font; + +public final class cf_ extends ListContainer implements ButtonListener { + private final AccountPage _K; + private final Font _J; + private final String _L; + private CommonUI.TickResult[] _N; + private int _G = 0; + private Button[] _E; + + public cf_(final AccountPage var1, final Font var2, final String var3) { + super(0, 0, 288, 0); + this._J = var2; + this._K = var1; + this._L = var3; + final int var4 = this._L != null ? this._J.measureParagraphHeight(this._L, 260, this._J.ascent) : 0; + this.setBounds(0, 0, 288, 22 + var4); + } + + public Button a700(final ComponentListener var1, final String var3) { + final Button var4 = new Button(var3, var1); + final int var5 = this.height - 2; + this.setBounds(0, 0, this.width, this.height + 34); + var4.setBounds(7, var5, this.width - 14, 30); + this.addChild(var4); + return var4; + } + + public void a966(final String var1, final CommonUI.TickResult var3) { + final int var4 = this._G; + this.b430(var4 + 1); + this._E[var4] = this.a700(this, var1); + this._N[var4] = var3; + } + + @Override + public void draw(final int x, final int y) { + super.draw(x, y); + this._J.drawParagraph(this._L, x + this.x + 14, 10 + this.y + y, this.width - 28, this.height, Drawing.WHITE, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, this._J.ascent); + } + + @Override + public void handleButtonClicked(final Button button) { + for (int var6 = 0; var6 < this._G; ++var6) { + if (button == this._E[var6]) { + final CommonUI.TickResult var7 = this._N[var6]; + if (var7 == null) { + this._K.i423(); + } else { + CommonUI._crb = this._N[var6]; + } + break; + } + } + + } + + private void b430(final int var1) { + if (var1 > this._G) { + final Button[] var3 = new Button[var1]; + final CommonUI.TickResult[] var4 = new CommonUI.TickResult[var1]; + + for (int var5 = 0; var5 < this._G; ++var5) { + var3[var5] = this._E[var5]; + var4[var5] = this._N[var5]; + } + + this._N = var4; + this._G = var1; + this._E = var3; + } + } +} diff --git a/src/main/java/funorb/commonui/cg_.java b/src/main/java/funorb/commonui/cg_.java new file mode 100644 index 0000000..19266ab --- /dev/null +++ b/src/main/java/funorb/commonui/cg_.java @@ -0,0 +1,35 @@ +package funorb.commonui; + +import funorb.commonui.container.WrapperContainer; +import funorb.graphics.Sprite; + +public final class cg_ extends WrapperContainer { + public int _J; + + public cg_() { + super(0, 0, 0, 0); + this._J = 256; + } + + public cg_(final Component var1) { + super(var1.x, var1.y, var1.width, var1.height); + var1.setBounds(0, 0, this.width, this.height); + this.child = var1; + this._J = 256; + } + + @Override + public void draw(final int x, final int y) { + if (this.child != null) { + if (this._J != 0) { + if (this._J == 256) { + this.child.draw(x + this.x, y + this.y); + } else { + final Sprite var5 = new Sprite(this.child.width, this.child.height); + var5.withInstalledForDrawingUsingOffsets(() -> this.child.draw(0, 0)); + var5.draw(x + this.x, y + this.y, this._J); + } + } + } + } +} diff --git a/src/main/java/funorb/commonui/container/ArrayContainer.java b/src/main/java/funorb/commonui/container/ArrayContainer.java new file mode 100644 index 0000000..8ad8237 --- /dev/null +++ b/src/main/java/funorb/commonui/container/ArrayContainer.java @@ -0,0 +1,227 @@ +package funorb.commonui.container; + +import funorb.awt.KeyState; +import funorb.commonui.Component; +import funorb.shatteredplans.client.JagexApplet; + +import java.util.Arrays; +import java.util.Hashtable; +import java.util.Objects; + +public abstract class ArrayContainer extends Component implements Container { + protected Component[] children; + + protected ArrayContainer() { + super(0, 0, 0, 0); + } + + private boolean a847(final Component var3) { + if (this.children != null) { + for (int var5 = this.children.length - 1; var5 >= 0; --var5) { + final Component var6 = this.children[var5]; + if (var6 != null && var6.isFocused()) { + for (var5 -= 1; var5 >= 0; var5 -= 1) { + final Component var7 = this.children[var5]; + if (var7 != null && var7.focus(var3)) { + return true; + } + } + } + } + + } + return false; + } + + @Override + public final boolean a931(final int var2, final int var3, final Component var4, final int var5, final int var6, final int var7) { + if (this.children != null) { + return Arrays.stream(this.children).anyMatch(var10 -> + var10 != null && var10.isFocused() && var10.a931(var2, var3, var4, var5, var6, var7)); + } + return false; + } + + @Override + public final boolean a686(final int keyCode, final char keyChar, final Component var4) { + if (this.children == null) { + return false; + } else { + + final Component[] var5 = this.children; + + for (final Component var7 : var5) { + if (var7 != null && var7.isFocused() && var7.a686(keyCode, keyChar, var4)) { + return true; + } + } + + if (keyCode == KeyState.Code.TAB) { + return !JagexApplet.keysDown[81] ? this.a948(var4) : this.a872(var4); + } else { + return false; + } + } + } + + private boolean a948(final Component var1) { + + return this.a766(var1); + } + + private void a801(final int var1, final StringBuilder var2, final Hashtable var3) { + if (this.children != null) { + final Component[] var5 = this.children; + + for (final Component var7 : var5) { + var2.append('\n'); + + var2.append(" ".repeat(Math.max(0, var1 + 1))); + + if (var7 == null) { + var2.append("null"); + } else { + var7.buildDebugString(var3, 1 + var1, var2); + } + } + + } + } + + @Override + public final void setBounds(final int x, final int y, final int width, final int height) { + super.setBounds(x, y, width, height); + this.h150(); + } + + @Override + public final void unfocus() { + final Component[] var2 = this.children; + + for (final Component var5 : var2) { + if (var5 != null) { + var5.unfocus(); + } + } + + } + + @Override + public void draw(final int x, final int y) { + if (this.renderer != null) { + this.renderer.draw(this, x, y, true); + } + + if (this.children != null) { + for (int var5 = this.children.length - 1; var5 >= 0; --var5) { + final Component var6 = this.children[var5]; + if (var6 != null) { + var6.draw(this.x + x, this.y + y); + } + } + } + + } + + @Override + public final boolean a446(final int var1, final int var2, final int var4, final int var5, final int var6, final Component var7) { + if (this.children != null) { + return Arrays.stream(this.children).anyMatch(var10 -> + var10 != null && var10.a446(var1, var2, var4, this.x + var5, this.y + var6, var7)); + } + return false; + } + + private Component a331() { + if (this.children != null) { + return Arrays.stream(this.children) + .filter(var4 -> var4 != null && var4.isFocused()) + .findFirst().orElse(null); + } + return null; + } + + @Override + public final boolean isFocused() { + return this.a331() != null; + } + + @Override + public final void a132(final int var1, final int var2, final int var3, final int var4, final Component var6) { + if (this.children != null) { + final Component[] var7 = this.children; + + for (final Component var9 : var7) { + if (var9 != null) { + var9.a132(var1, this.y + var2, var3 + this.x, var4, var6); + } + } + + } + } + + protected abstract void h150(); + + @Override + public final boolean focus(final Component previouslyFocused) { + return Arrays.stream(this.children).anyMatch(var6 -> var6 != null && var6.focus(previouslyFocused)); + } + + private boolean a766(final Component var1) { + if (this.children != null) { + for (int var4 = 0; this.children.length > var4; ++var4) { + final Component var5 = this.children[var4]; + if (var5 != null && var5.isFocused()) { + for (var4 += 1; var4 < this.children.length; var4 += 1) { + final Component var6 = this.children[var4]; + if (var6 != null && var6.focus(var1)) { + return true; + } + } + } + } + + } + return false; + } + + @Override + public void tick(final int x, final int y, final Component root) { + super.tick(x, y, root); + if (this.children != null) { + final Component[] var5 = this.children; + + for (final Component var7 : var5) { + if (var7 != null) { + var7.tick(this.x + x, y + this.y, root); + } + } + } + } + + private boolean a872(final Component var2) { + return this.a847(var2); + } + + @Override + public final StringBuilder buildDebugString(final Hashtable cycles, final int nestingLevel, final StringBuilder builder) { + if (this.debugStringCycleCheck(cycles, builder)) { + this.putDefaultDebugString(cycles, nestingLevel, builder); + this.a801(nestingLevel, builder, cycles); + } + + return builder; + } + + @Override + public final String getCurrentTooltip() { + if (this.children != null) { + return Arrays.stream(this.children) + .filter(Objects::nonNull) + .map(Component::getCurrentTooltip) + .filter(Objects::nonNull) + .findFirst().orElse(null); + } + return null; + } +} diff --git a/src/main/java/funorb/commonui/container/Container.java b/src/main/java/funorb/commonui/container/Container.java new file mode 100644 index 0000000..a9baf90 --- /dev/null +++ b/src/main/java/funorb/commonui/container/Container.java @@ -0,0 +1,4 @@ +package funorb.commonui.container; + +public interface Container { +} diff --git a/src/main/java/funorb/commonui/container/ListContainer.java b/src/main/java/funorb/commonui/container/ListContainer.java new file mode 100644 index 0000000..1be4cf7 --- /dev/null +++ b/src/main/java/funorb/commonui/container/ListContainer.java @@ -0,0 +1,157 @@ +package funorb.commonui.container; + +import funorb.awt.KeyState; +import funorb.commonui.Component; +import funorb.shatteredplans.client.JagexApplet; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; +import java.util.ListIterator; +import java.util.Optional; + +public class ListContainer extends Component implements Container { + protected final List children = new ArrayList<>(); + + protected ListContainer(final int x, final int y, final int width, final int height) { + super(x, y, width, height); + } + + @Override + public final boolean a931(final int var2, final int var3, final Component var4, final int var5, final int var6, final int var7) { + return this.children.stream().anyMatch(child -> child.isFocused() && child.a931(var2, var3, var4, var5, var6, var7)); + } + + @Override + public final boolean a446(final int var1, final int var2, final int var4, final int var5, final int var6, final Component var7) { + return this.children.stream().anyMatch(child -> child.a446(var1, var2, var4, var5 + this.x, var6 + this.y, var7)); + } + + protected final void removeChild(final Component child) { + this.children.remove(child); + } + + @Override + public boolean a686(final int keyCode, final char keyChar, final Component var4) { + if (this.children.stream().anyMatch(child -> child.isFocused() && child.a686(keyCode, keyChar, var4))) { + return true; + } + if (keyCode == KeyState.Code.TAB) { + return !JagexApplet.keysDown[81] ? this.a948(var4) : this.a611(var4); + } + return false; + } + + protected Component getFocusedChild() { + return this.children.stream().filter(Component::isFocused).findFirst().orElse(null); + } + + @Override + public void setBounds(final int x, final int y, final int width, final int height) { + super.setBounds(x, y, width, height); + this.h150(); + } + + private void a938(final StringBuilder var1, final Hashtable var2, final int var4) { + for (final Component child : this.children) { + var1.append('\n'); + var1.append(" ".repeat(Math.max(0, var4 + 1))); + child.buildDebugString(var2, var4 + 1, var1); + } + } + + @Override + public final boolean focus(final Component previouslyFocused) { + return this.children.stream().anyMatch(child -> child.focus(previouslyFocused)); + } + + protected final boolean a611(final Component var1) { + if (!this.children.isEmpty()) { + for (final ListIterator it1 = this.children.listIterator(this.children.size()); it1.hasPrevious();) { + final Component child1 = it1.previous(); + if (child1.isFocused()) { + for (final ListIterator it2 = this.children.listIterator(it1.nextIndex()); it2.hasPrevious();) { + final Component child2 = it2.previous(); + if (child2.focus(var1)) { + return true; + } + } + } + } + } + return false; + } + + protected final boolean a948(final Component var1) { + if (!this.children.isEmpty()) { + for (final ListIterator it1 = this.children.listIterator(); it1.hasNext(); ) { + final Component child1 = it1.next(); + if (child1.isFocused()) { + final ListIterator it2 = this.children.listIterator(it1.nextIndex()); + while (it2.hasNext()) { + final Component child2 = it2.next(); + if (child2.focus(var1)) { + return true; + } + } + } + } + } + return false; + } + + @Override + public void draw(final int x, final int y) { + super.draw(x, y); + + for (final ListIterator it = this.children.listIterator(this.children.size()); it.hasPrevious();) { + final Component child = it.previous(); + child.draw(this.x + x, this.y + y); + } + } + + @Override + public final StringBuilder buildDebugString(final Hashtable cycles, final int nestingLevel, final StringBuilder builder) { + if (this.debugStringCycleCheck(cycles, builder)) { + this.putDefaultDebugString(cycles, nestingLevel, builder); + this.a938(builder, cycles, nestingLevel); + } + + return builder; + } + + private void h150() { + this.children.forEach(Component::d423); + } + + protected final void addChild(final Component child) { + assert !this.children.contains(child); + this.children.add(child); + } + + @Override + public final void a132(final int var1, final int var2, final int var3, final int var4, final Component var6) { + this.children.forEach(child -> child.a132(var1, this.y + var2, var3 + this.x, var4, var6)); + } + + @Override + public final void unfocus() { + this.children.forEach(Component::unfocus); + } + + @Override + public String getCurrentTooltip() { + return this.children.stream().flatMap(var3 -> Optional.ofNullable(var3.getCurrentTooltip()).stream()).findFirst().orElse(null); + } + + @Override + public void tick(final int x, final int y, final Component root) { + super.tick(x, y, root); + this.children.forEach(child -> child.tick(this.x + x, this.y + y, root)); + } + + @Override + public final boolean isFocused() { + return this.getFocusedChild() != null; + } +} diff --git a/src/main/java/funorb/commonui/container/WrapperContainer.java b/src/main/java/funorb/commonui/container/WrapperContainer.java new file mode 100644 index 0000000..f02edfb --- /dev/null +++ b/src/main/java/funorb/commonui/container/WrapperContainer.java @@ -0,0 +1,142 @@ +package funorb.commonui.container; + +import funorb.awt.KeyState; +import funorb.commonui.Component; +import funorb.shatteredplans.client.JagexApplet; + +import java.util.Hashtable; + +public abstract class WrapperContainer extends Component implements Container { + protected Component child; + + protected WrapperContainer(final int var1, final int var2, final int var3, final int var4) { + super(var1, var2, var3, var4); + } + + private boolean a948(final Component var1) { + return this.child != null && !this.child.isFocused() && this.child.focus(var1); + } + + private void putChildDebugString(final Hashtable cycles, final int nestingLevel, final StringBuilder builder) { + builder.append('\n'); + builder.append(" ".repeat(Math.max(0, nestingLevel + 1))); + if (this.child == null) { + builder.append("null"); + } else { + this.child.buildDebugString(cycles, 1 + nestingLevel, builder); + } + } + + @Override + public final boolean focus(final Component previouslyFocused) { + return this.child != null && this.child.focus(previouslyFocused); + } + + @Override + public final void unfocus() { + if (this.child != null) { + this.child.unfocus(); + } + + } + + @Override + public void a132(final int var1, final int var2, final int var3, final int var4, final Component var6) { + if (this.child != null) { + this.child.a132(var1, this.y + var2, var3 + this.x, var4, var6); + } + + } + + private void h150() { + if (this.child != null) { + this.child.d423(); + } + + } + + @Override + public final boolean a931(final int var2, final int var3, final Component var4, final int var5, final int var6, final int var7) { + return this.child != null && this.child.isFocused() && this.child.a931(var2, var3, var4, var5, var6, var7); + } + + private boolean a872(final Component var2) { + + return this.child != null && !this.child.isFocused() && this.child.focus(var2); + } + + @Override + public final boolean isFocused() { + return this.a274() != null; + } + + @Override + public final void setBounds(final int x, final int y, final int width, final int height) { + super.setBounds(x, y, width, height); + this.h150(); + } + + @Override + public String getCurrentTooltip() { + assert true; + + final String var2 = super.getCurrentTooltip(); + if (this.child != null) { + final String var3 = this.child.getCurrentTooltip(); + if (var3 != null) { + return var3; + } + } + + return var2; + } + + @Override + public StringBuilder buildDebugString(final Hashtable cycles, final int nestingLevel, final StringBuilder builder) { + if (this.debugStringCycleCheck(cycles, builder)) { + this.putDefaultDebugString(cycles, nestingLevel, builder); + this.putChildDebugString(cycles, nestingLevel, builder); + } + return builder; + } + + @Override + public boolean a446(final int var1, final int var2, final int var4, final int var5, final int var6, final Component var7) { + return this.child != null && this.child.a446(var1, var2, var4, var5 + this.x, this.y + var6, var7); + } + + protected Component a274() { + return this.child != null && this.child.isFocused() ? this.child : null; + } + + @Override + public void tick(final int x, final int y, final Component root) { + super.tick(x, y, root); + if (this.child != null) { + this.child.tick(this.x + x, this.y + y, root); + } + + } + + @Override + public void draw(final int x, final int y) { + if (this.renderer != null) { + this.renderer.draw(this, x, y, true); + } + + if (this.child != null) { + this.child.draw(this.x + x, this.y + y); + } + } + + @Override + public final boolean a686(final int keyCode, final char keyChar, final Component var4) { + if (this.child != null && this.child.isFocused() && this.child.a686(keyCode, keyChar, var4)) { + return true; + } else if (keyCode == KeyState.Code.TAB) { + return !JagexApplet.keysDown[81] ? this.a948(var4) : this.a872(var4); + } else { + return false; + } + } +} diff --git a/src/main/java/funorb/commonui/form/CreateAccountForm.java b/src/main/java/funorb/commonui/form/CreateAccountForm.java new file mode 100644 index 0000000..5174e7d --- /dev/null +++ b/src/main/java/funorb/commonui/form/CreateAccountForm.java @@ -0,0 +1,251 @@ +package funorb.commonui.form; + +import funorb.Strings; +import funorb.awt.KeyState; +import funorb.client.JagexBaseApplet; +import funorb.commonui.Button; +import funorb.commonui.Checkbox; +import funorb.commonui.CommonUI; +import funorb.commonui.Component; +import funorb.commonui.Enum1; +import funorb.commonui.container.ListContainer; +import funorb.commonui.Resources; +import funorb.commonui.ah_; +import funorb.commonui.form.field.InputField; +import funorb.commonui.form.field.TextField; +import funorb.commonui.form.validator.AgeValidator; +import funorb.commonui.form.validator.ConfirmEmailValidator; +import funorb.commonui.form.validator.ConfirmPasswordValidator; +import funorb.commonui.form.validator.EmailValidator; +import funorb.commonui.form.validator.InputValidator; +import funorb.commonui.form.validator.PasswordValidator; +import funorb.commonui.form.validator.UsernameValidator; +import funorb.commonui.form.validator.ValidationState; +import funorb.commonui.hl_; +import funorb.commonui.listener.ButtonListener; +import funorb.commonui.CreateAccountPage; +import funorb.commonui.op_; +import funorb.commonui.pg_; +import funorb.commonui.renderer.LinkRenderer; +import funorb.commonui.renderer.PasswordFieldRenderer; +import funorb.commonui.renderer.TextRenderer; +import funorb.commonui.ts_; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.JagexApplet; + +import java.applet.Applet; + +public final class CreateAccountForm extends ListContainer implements op_, ButtonListener, CreateForm { + public static String _G; + public static String _cgF = null; + public static CreateAccountForm _anb; + private static boolean accountCreationFailed; + + public final CreateFormListener _D; + private final Button backButton = new Button(StringConstants.GO_BACK, new LinkRenderer(), null); + private final Button createButton = new Button(StringConstants.CREATE, null); + private final TextField usernameField = new TextField("", null, 12); + private final TextField emailField = new TextField("", null, 100); + private final TextField confirmEmailField = new TextField("", null, 100); + private final TextField passwordField = new TextField("", new PasswordFieldRenderer(), null, 20); + private final TextField confirmPasswordField = new TextField("", new PasswordFieldRenderer(), null, 20); + private final TextField ageField = new TextField("", null, 3); + private final Checkbox optInCheckbox = new Checkbox(true); + + private CreateAccountForm() { + super(0, 0, 496, 0); + this.usernameField.tooltip = StringConstants.CREATE_DISPLAYNAME_TOOLTIP; + this.emailField.tooltip = StringConstants.CREATE_EMAIL_TOOLTIP; + this.confirmEmailField.tooltip = StringConstants.CREATE_EMAIL_CONFIRM_TOOLTIP; + this.passwordField.tooltip = StringConstants.CREATE_PASSWORD_TOOLTIP; + this.confirmPasswordField.tooltip = StringConstants.CREATE_PASSWORD_CONFIRM_TOOLTIP; + this.ageField.tooltip = StringConstants.CREATE_AGE_TOOLTIP; + this.optInCheckbox.tooltip = StringConstants.CREATE_OPT_IN_NEWS_TOOLTIP; + this.usernameField.setValidator(new UsernameValidator(this.usernameField)); + this.emailField.setValidator(new EmailValidator(this.emailField)); + this.confirmEmailField.setValidator(new ConfirmEmailValidator(this.confirmEmailField, this.emailField)); + this.passwordField.setValidator(new PasswordValidator(this.passwordField, this.usernameField, this.emailField)); + this.confirmPasswordField.setValidator(new ConfirmPasswordValidator(this.confirmPasswordField, this.passwordField)); + this.ageField.setValidator(new AgeValidator(this.ageField)); + this.createButton.enabled = false; + + final String var2 = Strings.format(StringConstants.CREATE_AGREE_TERMS, "", "
"); + final byte var3 = 20; + int var8 = var3 + this.a187(StringConstants.CREATE_EMAIL, this.emailField, var3); + var8 += 5 + this.a986(var8, this.confirmEmailField, "", StringConstants.CREATE_EMAIL_CONFIRM, 20); + var8 += this.a187(StringConstants.CREATE_PASSWORD, this.passwordField, var8); + var8 += 5 + this.a244(StringConstants.CREATE_PASSWORD_HINT, var8, (byte) -127, this.confirmPasswordField, StringConstants.CREATE_PASSWORD_CONFIRM); + var8 += this.a244(StringConstants.CREATE_DIPLAY_NAME_HINT, var8, (byte) -128, this.usernameField, StringConstants.CREATE_DISPLAY_NAME) + 5; + var8 += this.a840(StringConstants.CREATE_AGE, this.ageField, var8); + final pg_ var4 = new pg_(46, var8, this.width - 90, this.optInCheckbox, true, this.width - 120, 5, Resources.AREZZO_12, 11579568, StringConstants.CREATE_OPT_IN_NEWS); + this.addChild(var4); + var8 += var4.height; + final TextRenderer var5 = new TextRenderer(Resources.AREZZO_14, 0, 0, 0, 0, Drawing.WHITE, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, Resources.AREZZO_14.ascent, true); + final ts_ _I = new ts_(var2, var5); + _I.tooltip = ""; + _I.a096(0, StringConstants.OPEN_IN_POPUP_WINDOW); + _I.a096(1, StringConstants.OPEN_IN_POPUP_WINDOW); + _I.listener = this; + _I.a652(46, var8, this.width - 90); + _I.pack(); + var8 += 15 + _I.height; + this.addChild(_I); + final byte var6 = 4; + final short var7 = 200; + this.createButton.setBounds(148, var8, var7, 40); + this.backButton.setBounds(7, 15 + var8, 60, 40); + this.backButton.listener = this; + this.createButton.listener = this; + this.addChild(this.createButton); + this.addChild(this.backButton); + this._D = new CreateFormListener(this); + this._D.setBounds(60 + this.usernameField.x + this.usernameField.width, this.usernameField.y + 20, -this.usernameField.x + this.width - 60 - this.usernameField.width, 150); + this.addChild(this._D); + this.setBounds(0, 0, 496, var8 + 55 + var6); + } + + public static void a984gm(final String var1) { + _cgF = var1; + CommonUI._crb = CommonUI.TickResult.R12; + } + + private static boolean a591js(final Applet var0) { + if (accountCreationFailed) { + return true; + } else { + return var0.getParameter("tuhstatbut") != null; + } + } + + public static void accountCreationFailed() { + accountCreationFailed = true; + } + + public static void a423tl() { + _anb = new CreateAccountForm(); + CommonUI._aef.b952(_anb); + } + + @Override + public void a746(final int var2) { + if (var2 == 0) { + a984gm("terms.ws"); + } else if (var2 == 1) { + a984gm("privacy.ws"); + } else if (var2 == 2) { + a984gm("conduct.ws"); + } + } + + private int a986(final int var3, final Component var4, final String var5, final String var6, final int var7) { + final pg_ var8 = new pg_(20, var3, 290, var4, false, 120, 3, Resources.AREZZO_14, Drawing.WHITE, var6); + this.addChild(var8); + final ah_ var9 = new ah_(((InputField) var4).getValidator(), var5, 126, var3 + var8.height, 220, var7); + var9.listener = this; + this.addChild(var9); + return var9.height + var8.height; + } + + private boolean a668(final InputField var2) { + final InputValidator var3 = var2.getValidator(); + if (var3 == null) { + return true; + } else { + final ValidationState var4 = var3.validate(); + + if (var4 == ValidationState.INVALID) { + return false; + } else if (var4 == ValidationState.CHECKING_2) { + return false; + } else { + return var4 != ValidationState.C5; + } + } + } + + private int a187(final String var1, final Component var3, final int var4) { + final pg_ var6 = new pg_(20, var4, 290, var3, false, 120, 3, Resources.AREZZO_14, Drawing.WHITE, var1); + + this.addChild(var6); + return var6.height; + } + + @Override + public void a984(final String var2) { + this.usernameField.a676(var2, false); + + } + + private int a244(final String var2, final int var3, final byte var4, final Component var5, final String var6) { + return var4 >= -126 ? -57 : this.a986(var3, var5, var2, var6, 35); + } + + @Override + public void a150() { + ((UsernameValidator) this.usernameField.getValidator()).d150(); + } + + @Override + public void tick(final int x, final int y, final Component root) { + super.tick(x, y, root); + this.createButton.enabled = this.m154(); + } + + @Override + public boolean a686(final int keyCode, final char keyChar, final Component var4) { + if (super.a686(keyCode, keyChar, var4)) { + return true; + } else if (keyCode == KeyState.Code.UP) { + return this.a611(var4); + } else { + return keyCode == KeyState.Code.DOWN && this.a948(var4); + } + } + + private int a840(final String var1, final Component var2, final int var3) { + final pg_ var6 = new pg_(20, var3, 290, var2, false, 120, 3, Resources.AREZZO_14, Drawing.WHITE, var1); + this.addChild(var6); + final hl_ var7 = new hl_(((InputField) var2).getValidator()); + this.addChild(var7); + var7.setBounds(var6.width + var6.x + 3, var6.y + (var6.height - 15 >> 1), 15, 15); + return var6.height; + } + + private boolean m154() { + return this.a668(this.usernameField) && this.a668(this.emailField) && this.a668(this.confirmEmailField) && this.a668(this.passwordField) && this.a668(this.confirmPasswordField) && this.a668(this.ageField); + } + + @Override + public void handleButtonClicked(final Button button) { + if (this.backButton == button) { + CommonUI.b423ol(); + } else if (button == this.createButton) { + if (this.m154()) { + int var2 = -1; + + try { + var2 = Integer.parseInt(this.ageField.text); + } catch (final NumberFormatException var4) { + } + + if (CommonUI._eel == Enum1.C1) { + final CreateAccountPage var6 = new CreateAccountPage(CommonUI.root, this); + CommonUI.root.pushChild(var6); + if (a591js(JagexBaseApplet.getInstance())) { + var6.f487(); + } else { + CommonUI._eel = Enum1.C3; + JagexApplet._npm = this.optInCheckbox.active; + _G = this.passwordField.text; + JagexApplet._umj = this.usernameField.text; + JagexApplet._tplc = null; + JagexApplet._aeg = this.emailField.text; + JagexApplet._jmt = var2; + } + } + } + } + } +} diff --git a/src/main/java/funorb/commonui/form/CreateDisplayNameForm.java b/src/main/java/funorb/commonui/form/CreateDisplayNameForm.java new file mode 100644 index 0000000..784533c --- /dev/null +++ b/src/main/java/funorb/commonui/form/CreateDisplayNameForm.java @@ -0,0 +1,132 @@ +package funorb.commonui.form; + +import funorb.awt.KeyState; +import funorb.commonui.Button; +import funorb.commonui.CommonUI; +import funorb.commonui.Component; +import funorb.commonui.Resources; +import funorb.commonui.ah_; +import funorb.commonui.container.ListContainer; +import funorb.commonui.form.field.InputField; +import funorb.commonui.form.field.TextField; +import funorb.commonui.form.validator.InputValidator; +import funorb.commonui.form.validator.UsernameValidator; +import funorb.commonui.form.validator.ValidationState; +import funorb.commonui.listener.ButtonListener; +import funorb.commonui.pg_; +import funorb.commonui.renderer.LinkRenderer; +import funorb.commonui.renderer.TextRenderer; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.shatteredplans.StringConstants; + +public final class CreateDisplayNameForm extends ListContainer implements CreateForm, ButtonListener { + public static String _frH; + public final CreateFormListener _F; + private final TextField _H = new TextField("", null, 12); + private final Button _G; + private final Button _I; + + public CreateDisplayNameForm() { + super(0, 0, 496, 0); + final TextRenderer var1 = new TextRenderer(Resources.AREZZO_12, 0, 0, 0, 0, Drawing.WHITE, Font.HorizontalAlignment.JUSTIFY, Font.VerticalAlignment.TOP, Resources.AREZZO_14.ascent, true); + final Component var2 = new Component(StringConstants.LOGIN_NO_DISPLAY_NAME, var1, null); + this._I = new Button(StringConstants.OK, null); + this._G = new Button(StringConstants.CANCEL, new LinkRenderer(), null); + this._H.tooltip = StringConstants.CREATE_DISPLAYNAME_TOOLTIP; + this._H.setValidator(new UsernameValidator(this._H)); + this._I.enabled = false; + final byte var3 = 20; + final byte var4 = 4; + final short var5 = 200; + var2.setBounds(20, var3, 270, 50); + this.addChild(var2); + int var6 = 70; + var6 += this.a516(var6, this._H, StringConstants.CREATE_DIPLAY_NAME_HINT, StringConstants.CREATE_DISPLAY_NAME) + 5; + this._I.setBounds(148, var6, var5, 40); + this._G.setBounds(7, var6 + 15, 60, 40); + this._G.listener = this; + this._I.listener = this; + this.addChild(this._I); + this.addChild(this._G); + this._F = new CreateFormListener(this); + this._F.setBounds(this._H.x - (-this._H.width - 60), 20, this.width - this._H.x + (-this._H.width - 60), 150); + this.addChild(this._F); + this.setBounds(0, 0, 496, 55 + var6 + var4); + } + + private int a649(final int var2, final Component var4, final String var5, final String var6) { + + final pg_ var8 = new pg_(20, var2, 290, var4, false, 120, 3, Resources.AREZZO_14, Drawing.WHITE, var6); + this.addChild(var8); + final ah_ var9 = new ah_(((InputField) var4).getValidator(), var5, 126, var8.height + var2, 195, 35); + var9.listener = this; + this.addChild(var9); + return var9.height + var8.height; + } + + @Override + public void tick(final int x, final int y, final Component root) { + super.tick(x, y, root); + this._I.enabled = this.k154(); + } + + @Override + public void a150() { + ((UsernameValidator) this._H.getValidator()).d150(); + } + + @Override + public void a984(final String var2) { + + this._H.a676(var2, false); + } + + private void a423() { + if (this.k154()) { + _frH = this._H.text; + CommonUI.setStateLoggingIn(StringConstants.LOGGING_IN, false); + } + } + + @Override + public void handleButtonClicked(final Button button) { + if (this._G == button) { + LoginForm.a487la(); + } else if (this._I == button) { + this.a423(); + } + + } + + private int a516(final int var3, final Component var4, final String var5, final String var6) { + return this.a649(var3, var4, var5, var6); + } + + private boolean k154() { + + return this.a294(this._H); + } + + @Override + public boolean a686(final int keyCode, final char keyChar, final Component var4) { + if (super.a686(keyCode, keyChar, var4)) { + return true; + } else if (keyCode == KeyState.Code.UP) { + return this.a611(var4); + } else { + + return keyCode == KeyState.Code.DOWN && this.a948(var4); + } + } + + private boolean a294(final InputField var1) { + final InputValidator var3 = var1.getValidator(); + if (var3 == null) { + return true; + } else { + final ValidationState var4 = var3.validate(); + return var4 == ValidationState.C2; + } + } +} diff --git a/src/main/java/funorb/commonui/form/CreateForm.java b/src/main/java/funorb/commonui/form/CreateForm.java new file mode 100644 index 0000000..e827cd9 --- /dev/null +++ b/src/main/java/funorb/commonui/form/CreateForm.java @@ -0,0 +1,6 @@ +package funorb.commonui.form; + +public interface CreateForm { + void a984(String var2); + void a150(); +} diff --git a/src/main/java/funorb/commonui/form/CreateFormListener.java b/src/main/java/funorb/commonui/form/CreateFormListener.java new file mode 100644 index 0000000..2ffbe29 --- /dev/null +++ b/src/main/java/funorb/commonui/form/CreateFormListener.java @@ -0,0 +1,84 @@ +package funorb.commonui.form; + +import funorb.awt.KeyState; +import funorb.commonui.Button; +import funorb.commonui.Component; +import funorb.commonui.Resources; +import funorb.commonui.container.ListContainer; +import funorb.commonui.listener.ButtonListener; +import funorb.commonui.renderer.LinkRenderer; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.ShatteredPlansClient; + +public final class CreateFormListener extends ListContainer implements ButtonListener { + private final CreateForm _F; + private Button[] _I; + private String[] _G; + + public CreateFormListener(final CreateForm var1) { + super(0, 0, 0, 0); + this._F = var1; + } + + @Override + public void draw(final int x, final int y) { + super.draw(x, y); + final Font var5 = Resources.AREZZO_14; + if (this._G != null) { + var5.drawParagraph(StringConstants.CREATE_SUGGESTIONS, x + this.x, this.y + y, this.width, 20, Drawing.WHITE, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, var5.descent + var5.ascent); + } + } + + @Override + public void handleButtonClicked(final Button button) { + for (int i = 0; i < this._G.length; ++i) { + if (button == this._I[i]) { + this._F.a984(this._G[i]); + } + } + if (button == this._I[this._G.length]) { + this._F.a150(); + } + } + + public void a449(final String[] var1) { + this.children.clear(); + if (var1 == null || var1.length == 0) { + this._G = null; + } else { + final int var3 = var1.length; + this._G = new String[var3]; + + for (int var4 = 0; var3 > var4; ++var4) { + this._G[var4] = ShatteredPlansClient.a034ih(var1[var4]).replace(' ', ' '); + } + + final LinkRenderer var6 = new LinkRenderer(Resources.AREZZO_14); + this._I = new Button[var3 + 1]; + + for (int var5 = 0; var3 > var5; ++var5) { + this._I[var5] = new Button(this._G[var5], var6, this); + this._I[var5].tooltip = StringConstants.CREATE_SELECT_ALTERNATIVE; + this._I[var5].setBounds(0, 20 + var5 * 16, 80, 15); + this.addChild(this._I[var5]); + } + + this._I[var3] = new Button(StringConstants.CREATE_MORE_SUGGESTIONS, var6, this); + this._I[var3].setBounds(0, 16 + var3 * 16 + 20, 100, 15); + this.addChild(this._I[var3]); + } + } + + @Override + public boolean a686(final int keyCode, final char keyChar, final Component var4) { + if (super.a686(keyCode, keyChar, var4)) { + return true; + } else if (keyCode == KeyState.Code.UP) { + return this.a611(var4); + } else { + return keyCode == KeyState.Code.DOWN && this.a948(var4); + } + } +} diff --git a/src/main/java/funorb/commonui/form/DobToEnableChatForm.java b/src/main/java/funorb/commonui/form/DobToEnableChatForm.java new file mode 100644 index 0000000..788b96c --- /dev/null +++ b/src/main/java/funorb/commonui/form/DobToEnableChatForm.java @@ -0,0 +1,68 @@ +package funorb.commonui.form; + +import funorb.commonui.container.ArrayContainer; +import funorb.commonui.Button; +import funorb.commonui.Component; +import funorb.commonui.Resources; +import funorb.commonui.form.field.DateField; +import funorb.commonui.form.validator.DateOfBirthValidator; +import funorb.commonui.form.validator.ValidationState; +import funorb.commonui.listener.ButtonListener; +import funorb.graphics.Drawing; +import funorb.shatteredplans.C2SPacket; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.JagexApplet; + +public final class DobToEnableChatForm extends ArrayContainer implements ButtonListener { + public static boolean _vaj; + public static DobToEnableChatForm instance; + private final DateField _J; + private final Button continueButton; + + public DobToEnableChatForm() { + super(); + this._J = new DateField(_vaj); + this._J.a890(new DateOfBirthValidator()); + this.continueButton = new Button(StringConstants.CONT, this); + this.children = new Component[]{this._J, this.continueButton}; + this.d423(); + } + + private static void a115vf(final int var0, final int var1, final int var3) { + JagexApplet.loginPacket.pos = 0; + JagexApplet.loginPacket.writeByte(12); + JagexApplet.loginPacket.writeInt(JagexApplet.cipherIVGen.nextInt()); + JagexApplet.loginPacket.writeInt(JagexApplet.cipherIVGen.nextInt()); + JagexApplet.loginPacket.writeByte(var3); + JagexApplet.loginPacket.writeByte(var1); + JagexApplet.loginPacket.writeShort(var0); + JagexApplet.loginPacket.encryptRSA(); + C2SPacket.a115vf2(); + } + + @Override + public void tick(final int x, final int y, final Component root) { + super.tick(x, y, root); + this.continueButton.enabled = this._J.getValidator().validate() == ValidationState.C2; + } + + @Override + public void h150() { + final short var2 = 250; + this._J.setBounds(-250 + this.width >> 1, this.height + 20 - 25 >> 1, 140, 25); + this.continueButton.setBounds(140 + (this.width - var2 >> 1) + 10, (this.height - 10 >> 1) + 2, 100, 30); + } + + @Override + public void draw(final int x, final int y) { + super.draw(x, y); + Resources.AREZZO_12.draw(StringConstants.DOB_ENTER_FOR_CHAT, this.x + x + 4, this.y + y + Resources.AREZZO_12.ascent + 4, Drawing.WHITE); + } + + @Override + public void handleButtonClicked(final Button button) { + if (this._J.getValidator().validate() == ValidationState.C2) { + a115vf(this._J.l137(), this._J.f410(), this._J.d474()); + } + } +} diff --git a/src/main/java/funorb/commonui/form/JustPlayForm.java b/src/main/java/funorb/commonui/form/JustPlayForm.java new file mode 100644 index 0000000..ec8f24b --- /dev/null +++ b/src/main/java/funorb/commonui/form/JustPlayForm.java @@ -0,0 +1,71 @@ +package funorb.commonui.form; + +import funorb.awt.KeyState; +import funorb.commonui.Button; +import funorb.commonui.CommonUI; +import funorb.commonui.Component; +import funorb.commonui.Resources; +import funorb.commonui.container.ListContainer; +import funorb.commonui.listener.ButtonListener; +import funorb.commonui.renderer.ButtonRenderer; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.shatteredplans.StringConstants; + +public final class JustPlayForm extends ListContainer implements ButtonListener { + private final Button justPlayButton; + private final Button backButton; + private final Button createAccountButton; + + public JustPlayForm() { + super(0, 0, 476, 225); + final ButtonRenderer var1 = new ButtonRenderer(); + this.createAccountButton = new Button(StringConstants.CREATE_CREATE_AN_ACCOUNT, var1, null); + this.backButton = new Button(StringConstants.GO_BACK, var1, null); + this.justPlayButton = new Button(StringConstants.JUST_PLAY, var1, null); + final int var2 = 4; + final int var3 = 326; + final int var4 = 161; + this.backButton.setBounds(-326 + this.width >> 1, this.height - 48 - var2, var4, 30); + this.justPlayButton.setBounds(var2 + var4 + (this.width - var3 >> 1), -52 + this.height, var4, 30); + this.createAccountButton.setBounds(this.width - var3 >> 1, this.height - 86, var3, 30); + this.backButton.listener = this; + this.createAccountButton.listener = this; + this.justPlayButton.listener = this; + this.createAccountButton.tooltip = StringConstants.LOGIN_CREATE_TOOLTIP; + this.justPlayButton.tooltip = StringConstants.LOGIN_JUST_PLAY_TOOLTIP; + this.addChild(this.backButton); + this.addChild(this.createAccountButton); + this.addChild(this.justPlayButton); + } + + @Override + public void draw(final int x, final int y) { + final int var5 = x + this.x; + final int var6 = y + this.y; + Resources.AREZZO_14.drawParagraph(StringConstants.CREATE_WELCOME, var5 + 20, var6 + 20, this.width - 40, this.height - 50, Drawing.WHITE, Font.HorizontalAlignment.CENTER, Font.VerticalAlignment.TOP, Resources.AREZZO_14.ascent); + super.draw(x, y); + } + + @Override + public boolean a686(final int keyCode, final char keyChar, final Component var4) { + if (super.a686(keyCode, keyChar, var4)) { + return true; + } else if (keyCode == KeyState.Code.UP) { + return this.a611(var4); + } else { + return keyCode == KeyState.Code.DOWN && this.a948(var4); + } + } + + @Override + public void handleButtonClicked(final Button button) { + if (button == this.backButton) { + LoginForm.a487la(); + } else if (button == this.createAccountButton) { + CreateAccountForm.a423tl(); + } else if (button == this.justPlayButton) { + CommonUI.a423oo(); + } + } +} diff --git a/src/main/java/funorb/commonui/form/LoginForm.java b/src/main/java/funorb/commonui/form/LoginForm.java new file mode 100644 index 0000000..0802bba --- /dev/null +++ b/src/main/java/funorb/commonui/form/LoginForm.java @@ -0,0 +1,207 @@ +package funorb.commonui.form; + +import funorb.awt.KeyState; +import funorb.commonui.AbstractTextField; +import funorb.commonui.Button; +import funorb.commonui.CommonUI; +import funorb.commonui.Component; +import funorb.commonui.container.ListContainer; +import funorb.commonui.Resources; +import funorb.commonui.form.field.TextField; +import funorb.commonui.listener.ButtonListener; +import funorb.commonui.listener.TextFieldListener; +import funorb.commonui.CreateAccountPage; +import funorb.commonui.pg_; +import funorb.commonui.renderer.ButtonRenderer; +import funorb.commonui.renderer.LinkRenderer; +import funorb.commonui.renderer.PasswordFieldRenderer; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.shatteredplans.StringConstants; + +public final class LoginForm extends ListContainer implements TextFieldListener, ButtonListener { + public static LoginForm _noe; + + private final boolean _L; + private final String _J; + private final Button cancelButton; + private final AbstractTextField usernameField; + private final AbstractTextField passwordField; + private final boolean isInitialLogin; + private final Button logInButton; + private Button _Q; + + public LoginForm(final String var1, final boolean var3, final boolean canCreateAccount, final boolean isInitialLogin) { + super(0, 0, 310, 190); + this._J = null; + this.isInitialLogin = isInitialLogin; + this._L = var3; + final ButtonRenderer var6 = new ButtonRenderer(); + if (!this._L || (!canCreateAccount && !this.isInitialLogin)) { + this.usernameField = new TextField(var1, this, 100); + this.passwordField = new TextField("", new PasswordFieldRenderer(), this, 20); + if (this._L) { + this.logInButton = new Button(StringConstants.RETRY, var6, null); + this.cancelButton = new Button(StringConstants.QUIT_TO_WEBSITE, var6, null); + this.usernameField.enabled = false; + } else { + this.logInButton = new Button(StringConstants.LOG_IN, var6, null); + final String cancelText = this.isInitialLogin ? StringConstants.JUST_PLAY : StringConstants.BACK; + this.cancelButton = new Button(cancelText, var6, null); + if (canCreateAccount) { + this._Q = new Button(StringConstants.CREATE_CREATE_AN_ACCOUNT, var6, this); + } + } + + this.usernameField.tooltip = StringConstants.LOGIN_USERNAME_TOOLTIP; + if (this._Q != null) { + this._Q.tooltip = StringConstants.LOGIN_CREATE_TOOLTIP; + } + + if (this._L) { + this.cancelButton.tooltip = StringConstants.WARNING_IF_YOU_QUIT; + } else { + if (this.isInitialLogin) { + this.cancelButton.tooltip = StringConstants.LOGIN_JUST_PLAY_TOOLTIP; + } + this.cancelButton.renderer = new LinkRenderer(); + } + + this.y = 15; + final Font var7 = Resources.AREZZO_14; + + final String var8 = StringConstants.LOGIN_USERNAME_EMAIL; + + pg_ var10; + this.addChild(var10 = new pg_(10, this.y, this.width - 20, this.usernameField, false, 80, 3, var7, Drawing.WHITE, var8)); + this.y += var10.height + 5; + this.addChild(var10 = new pg_(10, this.y, this.width - 20, this.passwordField, false, 80, 3, var7, Drawing.WHITE, StringConstants.CREATE_PASSWORD)); + this.y += var10.height + 5; + this.logInButton.listener = this; + if (this._Q != null) { + this._Q.listener = this; + } + + this.cancelButton.listener = this; + + if (this._Q == null) { + this.logInButton.setBounds(8, this.y, this.width - 10 - 6, 30); + this.y += 35; + } else { + this.logInButton.setBounds(85, this.y, this.width - 95, 30); + this.y += 60; + } + + if (this._Q != null) { + this._Q.setBounds(8, this.y, this.width - 16, 30); + this.y += 35; + } + + if (this._L || this.isInitialLogin) { + this.cancelButton.setBounds(8, this.y, this.width - 10 - 6, 30); + this.y += 35; + } else { + this.cancelButton.setBounds(8, this.y, 40, 20); + this.y += 25; + } + + this.setBounds(0, 0, this.width, this.y + 3); + this.addChild(this.logInButton); + if (this._Q != null) { + this.addChild(this._Q); + } + + this.addChild(this.cancelButton); + + } else { + throw new IllegalStateException(); + } + } + + public static void a667ce(final String var0) { + if (CommonUI._jiG != null) { + CommonUI._jiG.i423(); + } + _noe = new LoginForm(var0, false, true, true); + CommonUI._aef.b952(_noe); + } + + public static void a487la() { + a667ce(""); + } + + public void a984(final String var2) { + this.usernameField.a676(var2, false); + this.passwordField.e487(); + } + + @Override + public boolean a686(final int keyCode, final char keyChar, final Component var4) { + if (super.a686(keyCode, keyChar, var4)) { + return true; + } else if (keyCode == KeyState.Code.UP) { + return this.a611(var4); + } else { + return keyCode == KeyState.Code.DOWN && this.a948(var4); + } + } + + @Override + public void handleTextFieldChanged() { + } + + private void submit() { + if (CommonUI._nlb || (this.usernameField.text.length() > 0 && this.passwordField.text.length() > 0)) { + CreateAccountPage.a584ai(this.usernameField.text, this.passwordField.text, false); + } + } + + @Override + public void draw(final int x, final int y) { + if (this._J != null) { + Resources.AREZZO_14.drawParagraph(this._J, 20 + x + this.x, 15 + this.y + y, this.width - 40, this.height, Drawing.WHITE, Font.HorizontalAlignment.CENTER, Font.VerticalAlignment.TOP, Resources.AREZZO_14.ascent); + } + + if (this._Q != null) { + Drawing.horizontalLine(x + 10, 134 + y, this.width - 20, 4210752); + } + + super.draw(x, y); + } + + @Override + public void handleTextFieldEnterPressed(final AbstractTextField textField) { + if (textField == this.usernameField) { + this.passwordField.focus(this); + } + if (textField == this.passwordField) { + this.submit(); + } + } + + @Override + public void handleButtonClicked(final Button button) { + if (this.logInButton == button) { + this.submit(); + } else if (this._Q == button) { + CreateAccountForm.a423tl(); + } else if (this.cancelButton == button) { + if (this._L) { + CommonUI._crb = CommonUI.TickResult.QUIT_TO_WEBSITE; + } else if (this.isInitialLogin) { + CommonUI.b423ol(); + } else { + CommonUI._crb = CommonUI.TickResult.R4; + } + } + } + + public String d791() { + return this.usernameField.text == null ? "" : this.usernameField.text; + } + + public void l150() { + this.usernameField.e487(); + this.passwordField.e487(); + } +} diff --git a/src/main/java/funorb/commonui/form/field/AbstractDateField.java b/src/main/java/funorb/commonui/form/field/AbstractDateField.java new file mode 100644 index 0000000..0b0e71c --- /dev/null +++ b/src/main/java/funorb/commonui/form/field/AbstractDateField.java @@ -0,0 +1,31 @@ +package funorb.commonui.form.field; + +import funorb.commonui.form.validator.DateOfBirthValidator; +import funorb.commonui.form.validator.InputValidator; +import funorb.commonui.container.ListContainer; + +public abstract class AbstractDateField extends ListContainer implements InputField { + private DateOfBirthValidator _H; + + protected AbstractDateField() { + super(0, 0, 0, 0); + } + + public abstract int d474(); + + public abstract int f410(); + + @Override + public final InputValidator getValidator() { + return this._H; + } + + protected void a890(final DateOfBirthValidator var1) { + this._H = var1; + this._H._m = this; + } + + public abstract boolean k154(); + + public abstract int l137(); +} diff --git a/src/main/java/funorb/commonui/form/field/DateField.java b/src/main/java/funorb/commonui/form/field/DateField.java new file mode 100644 index 0000000..517ff2e --- /dev/null +++ b/src/main/java/funorb/commonui/form/field/DateField.java @@ -0,0 +1,125 @@ +package funorb.commonui.form.field; + +import funorb.commonui.AbstractTextField; +import funorb.commonui.Component; +import funorb.commonui.Resources; +import funorb.commonui.form.validator.DateOfBirthValidator; +import funorb.graphics.Drawing; +import funorb.shatteredplans.StringConstants; + +public final class DateField extends AbstractDateField { + private final AbstractTextField _R; + private final AbstractTextField _O; + private final boolean _J; + private final AbstractTextField _M; + + public DateField(final boolean var2) { + super(); + this._O = new TextField("", null, 2); + this._M = new TextField("", null, 2); + this._R = new TextField("", null, 4); + this._J = var2; + if (this._J) { + this.addChild(this._M); + this.addChild(this._O); + } else { + this.addChild(this._O); + this.addChild(this._M); + } + + this.addChild(this._R); + this.setBounds(0, 0, 140, 25); + } + + private void a811(final int var1, final Component var3, final String var4, final int var5) { + Resources.AREZZO_12.drawCentered(var4, var1 - (-var3.x - (var3.width >> 1)), var3.y + var5 - 5, Drawing.WHITE); + } + + @Override + public void setBounds(final int x, final int y, final int width, final int height) { + super.setBounds(x, y, width, height); + final int var6 = width - 130 >> 1; + if (this._J) { + assert this._M != null; + this._M.setBounds(var6, 0, 25, height); + this._O.setBounds(45 + var6, 0, 25, height); + } else { + this._O.setBounds(var6, 0, 25, height); + this._M.setBounds(var6 + 45, 0, 25, height); + } + + this._R.setBounds(90 + var6, 0, 40, height); + } + + @Override + public String getCurrentTooltip() { + assert true; + + final String var2 = this._M.getCurrentTooltip(); + if (var2 != null) { + return var2; + } else if (this.isMouseOver) { + return this.tooltip == null ? this.text : this.tooltip; + } else { + return null; + } + } + + @Override + public boolean k154() { + if (this._O.text == null || this._O.text.length() == 0) { + return true; + } else if (this._M.text == null || this._M.text.length() == 0) { + return true; + } else { + return this._R.text == null || this._R.text.length() == 0; + } + } + + @Override + public int l137() { + try { + return Integer.parseInt(this._R.text); + } catch (final NumberFormatException var3) { + return -1; + } + } + + @Override + public int f410() { + try { + return Integer.parseInt(this._M.text) - 1; + } catch (final NumberFormatException var4) { + return -1; + } + } + + @Override + public void a890(final DateOfBirthValidator var1) { + super.a890(var1); + + this._O.listener = var1; + assert this._M != null; + this._M.listener = var1; + this._R.listener = var1; + } + + @Override + public void draw(int x, int y) { + super.draw(x, y); + y += this.y; + x += this.x; + this.a811(x, this._O, StringConstants.DAY, y); + this.a811(x, this._M, StringConstants.MONTH, y); + this.a811(x, this._R, StringConstants.YEAR, y); + } + + @Override + public int d474() { + try { + return Integer.parseInt(this._O.text); + } catch (final NumberFormatException var3) { + return -1; + } + } +} diff --git a/src/main/java/funorb/commonui/form/field/InputField.java b/src/main/java/funorb/commonui/form/field/InputField.java new file mode 100644 index 0000000..844e426 --- /dev/null +++ b/src/main/java/funorb/commonui/form/field/InputField.java @@ -0,0 +1,7 @@ +package funorb.commonui.form.field; + +import funorb.commonui.form.validator.InputValidator; + +public interface InputField { + InputValidator getValidator(); +} diff --git a/src/main/java/funorb/commonui/form/field/TextField.java b/src/main/java/funorb/commonui/form/field/TextField.java new file mode 100644 index 0000000..2d31c8e --- /dev/null +++ b/src/main/java/funorb/commonui/form/field/TextField.java @@ -0,0 +1,56 @@ +package funorb.commonui.form.field; + +import funorb.commonui.Component; +import funorb.commonui.form.validator.InputValidator; +import funorb.commonui.AbstractTextField; +import funorb.commonui.listener.ComponentListener; +import funorb.commonui.renderer.ComponentRenderer; +import funorb.commonui.renderer.TextFieldRenderer; +import funorb.commonui.TooltipManager; +import funorb.shatteredplans.client.JagexApplet; + +public final class TextField extends AbstractTextField implements InputField { + private InputValidator validator; + private int _U; + + public TextField(final String text, final ComponentListener listener, final int var3) { + this(text, new TextFieldRenderer(), listener, var3); + } + + public TextField(final String text, final ComponentRenderer renderer, final ComponentListener listener, final int var3) { + super(text, renderer, listener, var3); + } + + @Override + public void tick(final int x, final int y, final Component root) { + super.tick(x, y, root); + this._U = JagexApplet.mouseX - (this.x + x); + } + + @Override + public String getCurrentTooltip() { + if (this.isMouseOver && this.tooltip != null) { + TooltipManager.INSTANCE.setMousePosition(this.width - this._U + JagexApplet.mouseX, JagexApplet.mouseY); + return this.tooltip; + } else { + return null; + } + } + + @Override + protected void i150() { + super.i150(); + if (this.validator != null) { + this.validator.b150(); + } + } + + public void setValidator(final InputValidator validator) { + this.validator = validator; + } + + @Override + public InputValidator getValidator() { + return this.validator; + } +} diff --git a/src/main/java/funorb/commonui/form/validator/AbstractInputValidator.java b/src/main/java/funorb/commonui/form/validator/AbstractInputValidator.java new file mode 100644 index 0000000..6750f0d --- /dev/null +++ b/src/main/java/funorb/commonui/form/validator/AbstractInputValidator.java @@ -0,0 +1,34 @@ +package funorb.commonui.form.validator; + +import funorb.util.PseudoMonotonicClock; + +public abstract class AbstractInputValidator implements InputValidator { + private long _b; + + protected abstract ValidationState a083(); + + @Override + public final String a983() { + if (this.a154()) { + return null; + } else { + return PseudoMonotonicClock.currentTimeMillis() >= this._b + 350L ? this.c983() : null; + } + } + + @Override + public final void b150() { + this._b = PseudoMonotonicClock.currentTimeMillis(); + } + + @Override + public final ValidationState validate() { + if (this.a154()) { + return ValidationState.C5; + } else { + return this._b + 350L <= PseudoMonotonicClock.currentTimeMillis() ? this.a083() : ValidationState.CHECKING_2; + } + } + + protected abstract String c983(); +} diff --git a/src/main/java/funorb/commonui/form/validator/AgeValidator.java b/src/main/java/funorb/commonui/form/validator/AgeValidator.java new file mode 100644 index 0000000..bd9abce --- /dev/null +++ b/src/main/java/funorb/commonui/form/validator/AgeValidator.java @@ -0,0 +1,26 @@ +package funorb.commonui.form.validator; + +import funorb.Strings; +import funorb.commonui.AbstractTextField; +import funorb.shatteredplans.StringConstants; + +public final class AgeValidator extends StringValidator { + public AgeValidator(final AbstractTextField var1) { + super(var1); + } + + @Override + public String a751(final String var2) { + return this.b492(var2) != ValidationState.INVALID ? null : StringConstants.CREATE_ALERT_INVALID_AGE; + } + + @Override + protected ValidationState b492(final String var2) { + if (Strings.a783wk(var2)) { + final int var3 = Strings.parseDecimalInteger(var2); + return var3 > 0 && var3 <= 130 ? ValidationState.C2 : ValidationState.INVALID; + } else { + return ValidationState.INVALID; + } + } +} diff --git a/src/main/java/funorb/commonui/form/validator/ConfirmEmailValidator.java b/src/main/java/funorb/commonui/form/validator/ConfirmEmailValidator.java new file mode 100644 index 0000000..ce8a798 --- /dev/null +++ b/src/main/java/funorb/commonui/form/validator/ConfirmEmailValidator.java @@ -0,0 +1,53 @@ +package funorb.commonui.form.validator; + +import funorb.commonui.AbstractTextField; +import funorb.commonui.ks_; +import funorb.shatteredplans.StringConstants; + +public final class ConfirmEmailValidator extends StringValidator { + public static ks_ _wha; + private final ConfirmPasswordValidator _s; + private boolean _n = false; + private String _t = ""; + + public ConfirmEmailValidator(final AbstractTextField var1, final AbstractTextField var2) { + super(var1); + this._s = new ConfirmPasswordValidator(var1, var2); + } + + private static ks_ a661os(final String var1) { + if (_wha.b154() && !var1.equals(_wha.a738())) { + _wha = new ks_(var1); + } + return _wha; + } + + @Override + public String a751(final String var2) { + if (this._s.b492(var2) == ValidationState.INVALID) { + return this._s.a751(var2); + } else { + return this.b492(var2) != ValidationState.INVALID ? StringConstants.CREATE_EMAIL_VALID : StringConstants.CREATE_ALERT_EMAIL_UNAVAILABLE; + } + } + + @Override + protected ValidationState b492(final String var2) { + if (this._s.b492(var2) == ValidationState.INVALID) { + return ValidationState.INVALID; + } else { + if (!var2.equals(this._t)) { + final ks_ var3 = a661os(var2); + if (!var3.b154()) { + return ValidationState.CHECKING_1; + } + + this._t = var2; + this._n = var3.a491(); + } + + return this._n ? ValidationState.C2 : ValidationState.INVALID; + } + } + +} diff --git a/src/main/java/funorb/commonui/form/validator/ConfirmPasswordValidator.java b/src/main/java/funorb/commonui/form/validator/ConfirmPasswordValidator.java new file mode 100644 index 0000000..88f7afe --- /dev/null +++ b/src/main/java/funorb/commonui/form/validator/ConfirmPasswordValidator.java @@ -0,0 +1,43 @@ +package funorb.commonui.form.validator; + +import funorb.commonui.form.field.InputField; +import funorb.commonui.AbstractTextField; +import funorb.shatteredplans.StringConstants; + +public final class ConfirmPasswordValidator extends StringValidator { + private final AbstractTextField _n; + + public ConfirmPasswordValidator(final AbstractTextField var1, final AbstractTextField var2) { + super(var1); + this._n = var2; + } + + @Override + public String a751(final String var2) { + if (this._n instanceof InputField) { + final InputValidator var3 = ((InputField) this._n).getValidator(); + if (var3 != null) { + if (var3.validate() == ValidationState.C2 && !var2.equals(this._n.text)) { + return StringConstants.CREATE_ALERT_MISMATCH; + } + + return var3.a983(); + } + } + + return var2.equals(this._n.text) ? null : StringConstants.CREATE_ALERT_MISMATCH; + } + + @Override + public ValidationState b492(final String var2) { + if (this._n instanceof InputField) { + final InputValidator var3 = ((InputField) this._n).getValidator(); + if (var3 != null && var3.validate() != ValidationState.C2) { + return ValidationState.INVALID; + } + } + + return var2.equals(this._n.text) ? ValidationState.C2 : ValidationState.INVALID; + } + +} diff --git a/src/main/java/funorb/commonui/form/validator/DateOfBirthValidator.java b/src/main/java/funorb/commonui/form/validator/DateOfBirthValidator.java new file mode 100644 index 0000000..06085c1 --- /dev/null +++ b/src/main/java/funorb/commonui/form/validator/DateOfBirthValidator.java @@ -0,0 +1,108 @@ +package funorb.commonui.form.validator; + +import funorb.Strings; +import funorb.commonui.form.field.AbstractDateField; +import funorb.commonui.g_; +import funorb.commonui.AbstractTextField; +import funorb.commonui.listener.TextFieldListener; +import funorb.shatteredplans.StringConstants; + +import java.util.Date; + +public final class DateOfBirthValidator extends AbstractInputValidator implements TextFieldListener, g_ { + private static final int[] _jab = new int[]{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + public AbstractDateField _m; + + public DateOfBirthValidator() { + } + + private static boolean a648tg(final int var0, final int var1, final int var2) { + if (var1 >= 0 && var1 <= 11) { + return var0 >= 1 && a666oq(var2, var1) >= var0; + } else { + return false; + } + } + + private static int a666oq(final int var0, final int var1) { + return var1 == 1 && a560qe(var0) ? 29 : _jab[var1]; + } + + private static boolean a560qe(final int var0) { + if (var0 < 0) { + return (1 + var0) % 4 == 0; + } else if (var0 < 1582) { + return var0 % 4 == 0; + } else if (var0 % 4 != 0) { + return false; + } else if (var0 % 100 == 0) { + return var0 % 400 == 0; + } else { + return true; + } + } + + private static int e137() { + return (new Date()).getYear() + 1900; + } + + @Override + public void handleTextFieldChanged() { + this.b150(); + } + + @Override + public String c983() { + try { + final int var2 = this._m.d474(); + final int var3 = this._m.f410(); + + final int var4 = this._m.l137(); + final int var5 = e137(); + if (var4 < 1890 || var4 > var5 - 3) { + return Strings.format(StringConstants.CREATE_ALERT_YEAR_RANGE, "1890", Integer.toString(var5 - 3)); + } + + if (a648tg(var2, var3, var4)) { + return null; + } + } catch (final NumberFormatException var6) { + } + + return StringConstants.CREATE_ALERT_INVALID_DATE; + } + + @Override + public ValidationState a083() { + try { + final int var2 = this._m.d474(); + final int var3 = this._m.f410(); + final int var4 = this._m.l137(); + final int var5 = e137(); + if (var4 < 1890) { + return ValidationState.INVALID; + } + + if (var5 - 3 < var4) { + return ValidationState.INVALID; + } + + if (!a648tg(var2, var3, var4)) { + return ValidationState.INVALID; + } + } catch (final NumberFormatException var6) { + return ValidationState.INVALID; + } + + return ValidationState.C2; + } + + @Override + public void handleTextFieldEnterPressed(final AbstractTextField textField) { + } + + @Override + public boolean a154() { + return this._m.k154(); + } +} diff --git a/src/main/java/funorb/commonui/form/validator/EmailValidator.java b/src/main/java/funorb/commonui/form/validator/EmailValidator.java new file mode 100644 index 0000000..b33b0c8 --- /dev/null +++ b/src/main/java/funorb/commonui/form/validator/EmailValidator.java @@ -0,0 +1,163 @@ +package funorb.commonui.form.validator; + +import funorb.commonui.AbstractTextField; +import funorb.shatteredplans.StringConstants; + +public final class EmailValidator extends StringValidator { + private static final String _hrc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&'*+-/=?^_{}~"; + private static final String _maq = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + public EmailValidator(final AbstractTextField var1) { + super(var1); + } + + private static Enum5 a621(final String var0) { + final int var1 = var0.length(); + if (var1 == 0) { + return Enum5.C2; + } else if (var1 > 255) { + return Enum5.C1; + } else { + final String[] var2 = var0.split("\\."); + if (var2.length >= 2) { + + for (final String var5 : var2) { + final Enum5 var6 = a761w(var5); + if (var6 != null) { + return var6; + } + } + + return a003oq(var2[var2.length - 1]); + } else { + return Enum5.C2; + } + } + } + + private static Enum5 a264vn(final String var1) { + if (var1 == null || var1.length() == 0) { + return Enum5.C4; + } else { + final int var2 = var1.indexOf((char) 64); + if (var2 == -1) { + return Enum5.C2; + } else { + final String var3 = var1.substring(0, var2); + final String var4 = var1.substring(var2 + 1); + final Enum5 var5 = a264uc(var3); + return var5 != null ? var5 : a621(var4); + } + } + } + + private static Enum5 a761w(final String var0) { + final int var1 = var0.length(); + if (var1 == 0) { + return Enum5.C2; + } else if (var1 > 63) { + return Enum5.C1; + } else { + for (int var3 = 0; var3 < var1; ++var3) { + final char var4 = var0.charAt(var3); + if (var4 != '-') { + if (_maq.indexOf(var4) == -1) { + return Enum5.C3; + } + } else if (var3 == 0 || var1 - 1 == var3) { + return Enum5.C3; + } + } + + return null; + } + } + + private static Enum5 a003oq(final String var0) { + final int var1 = var0.length(); + + for (int var2 = 0; var1 > var2; ++var2) { + final char var3 = var0.charAt(var2); + if (var3 < '0' || var3 > '9') { + return null; + } + } + + return Enum5.C3; + } + + private static Enum5 a264uc(final String var0) { + final int var1 = var0.length(); + if (var1 == 0) { + return Enum5.C2; + } else if (var1 > 64) { + return Enum5.C1; + } else { + boolean var2; + int var3; + char var4; + if (var0.charAt(0) == '"') { + if (var0.charAt(var1 - 1) == '"') { + var2 = false; + + for (var3 = 1; var1 - 1 > var3; ++var3) { + var4 = var0.charAt(var3); + if (var4 == '\\') { + var2 = !var2; + } else { + if (var4 == '"' && !var2) { + return Enum5.C3; + } + + var2 = false; + } + } + + return null; + } else { + return Enum5.C3; + } + } else { + var2 = false; + + for (var3 = 0; var3 < var1; ++var3) { + var4 = var0.charAt(var3); + if (var4 == '.') { + if (var3 == 0 || var3 == var1 - 1 || var2) { + return Enum5.C3; + } + + var2 = true; + } else { + if (_hrc.indexOf(var4) == -1) { + return Enum5.C3; + } + + var2 = false; + } + } + + return null; + } + } + } + + @Override + public String a751(final String var2) { + if (this.b492(var2) == ValidationState.INVALID) { + return StringConstants.CREATE_ALERT_INVALID_EMAIL; + } else { + return StringConstants.CREATE_EMAIL_VALID; + } + } + + @Override + protected ValidationState b492(final String var2) { + final boolean var3 = a264vn(var2) == null; + return var3 ? ValidationState.C2 : ValidationState.INVALID; + } + + private enum Enum5 { + C1, C2, C3, C4 + } +} diff --git a/src/main/java/funorb/commonui/form/validator/InputValidator.java b/src/main/java/funorb/commonui/form/validator/InputValidator.java new file mode 100644 index 0000000..c2b1172 --- /dev/null +++ b/src/main/java/funorb/commonui/form/validator/InputValidator.java @@ -0,0 +1,11 @@ +package funorb.commonui.form.validator; + +public interface InputValidator { + String a983(); + + boolean a154(); + + ValidationState validate(); + + void b150(); +} diff --git a/src/main/java/funorb/commonui/form/validator/PasswordValidator.java b/src/main/java/funorb/commonui/form/validator/PasswordValidator.java new file mode 100644 index 0000000..caf32f6 --- /dev/null +++ b/src/main/java/funorb/commonui/form/validator/PasswordValidator.java @@ -0,0 +1,181 @@ +package funorb.commonui.form.validator; + +import funorb.Strings; +import funorb.commonui.AbstractTextField; +import funorb.shatteredplans.StringConstants; + +import java.util.stream.IntStream; + +public final class PasswordValidator extends StringValidator { + private static final int _npo = 5; + private final AbstractTextField _o; + private final AbstractTextField _q; + + public PasswordValidator(final AbstractTextField var1, final AbstractTextField var2, final AbstractTextField var3) { + super(var1); + this._o = var3; + this._q = var2; + } + + private static boolean a623nc(final String var0) { + final char var1 = var0.charAt(0); + return IntStream.range(1, var0.length()).noneMatch(var2 -> var1 != var0.charAt(var2)); + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + private static boolean a014na(final String var0, final String var2a) { + final String var2 = a229fr(var2a); + final String var3 = a005dn(var2); + return var0.contains(var2) || var0.contains(var3); + } + + private static boolean a014gi(final String var0, final String var2) { + if (a896hb(var0)) { + return false; + } else if (a623nc(var0)) { + return false; + } else if (a988cg(var0)) { + return false; + } else if (var2.length() == 0) { + return true; + } else if (a014va(var2, var0)) { + return false; + } else if (a405ms(var0, var2)) { + return false; + } else { + return !a014na(var0, var2); + } + } + + private static boolean a896hb(final String var0) { + for (int var1 = 0; var1 < var0.length(); ++var1) { + final char var2 = var0.charAt(var1); + if (!Strings.isAlpha(var2) && !Strings.isDigit(var2)) { + return true; + } + } + + return false; + } + + private static String a005dn(final String var0) { + final int var1 = var0.length(); + final char[] var2 = new char[var1]; + + for (int var3 = 0; var1 > var3; ++var3) { + var2[-var3 + var1 - 1] = var0.charAt(var3); + } + + return new String(var2); + } + + private static boolean a988cg(final String var0) { + return var0 == null || var0.length() < _npo || var0.length() > 20; + } + + private static boolean a014va(final String var0, final String var2) { + final String var3 = a005dn(var0); + if (var2.contains(var0) || var2.contains(var3)) { + return true; + } else { + return var2.startsWith(var0) || var2.startsWith(var3) || var2.endsWith(var0) || var2.endsWith(var3); + } + } + + private static boolean a405ms(final String var0, String var2) { + var2 = a229fr(var2); + final String var3 = a005dn(var0); + return var2.contains(var0) || var2.contains(var3); + } + + private static String a229fr(final String var0) { + final int var4 = var0.length(); + final int var5 = "".length(); + int var6 = var4; + final int var7 = var5 - 1; + int var8 = 0; + + while (true) { + var8 = var0.indexOf('_', var8); + if (var8 < 0) { + break; + } + + var6 += var7; + ++var8; + } + + final StringBuilder var11 = new StringBuilder(var6); + int var9 = 0; + + while (true) { + final int var10 = var0.indexOf('_', var9); + if (var10 < 0) { + var11.append(var0.substring(var9)); + return var11.toString(); + } + + var11.append(var0, var9, var10); + var9 = var10 + 1; + } + } + + private boolean b213(final String var2) { + final String var3 = this._o.text.toLowerCase(); + final String var4 = var2.toLowerCase(); + if (var3.length() > 0 && var4.length() > 0) { + final int var5 = var3.lastIndexOf("@"); + if (var5 >= 0 && var5 < var3.length() - 1) { + final String var6 = var3.substring(0, var5); + final String var7 = var3.substring(var5 + 1); + if (var4.contains(var6)) { + return true; + } + + return var4.contains(var7); + } + } + + return false; + } + + @Override + public ValidationState b492(final String var2) { + final String var3 = this._q.text.toLowerCase(); + final String var4 = var2.toLowerCase(); + if (var4.length() == 0) { + return ValidationState.INVALID; + } else if (a014gi(var4, var3)) { + return !this.b213(var2) ? ValidationState.C2 : ValidationState.INVALID; + } else { + return ValidationState.INVALID; + } + } + + @Override + public String a751(final String var2) { + final String var3 = this._q.text.toLowerCase(); + final String var4 = var2.toLowerCase(); + if (var4.length() == 0) { + return null; + } else if (a988cg(var4)) { + return StringConstants.CREATE_ALERT_PASS_LENGTH; + } else if (a896hb(var4)) { + return StringConstants.CREATE_ALERT_PASSCHARS; + } else if (a623nc(var4)) { + return StringConstants.CREATE_ALERT_PASS_REPEATED; + } else if (this.b213(var2)) { + return StringConstants.CREATE_ALERT_PASS_CONTAINS_EMAIL; + } else if (var3.length() > 0) { + if (a014va(var3, var4)) { + return StringConstants.CREATE_ALERT_PASS_CONTAINS_NAME; + } else if (a405ms(var4, var3)) { + return StringConstants.CREATE_ALERT_PASS_CONTAINS_NAME_PARTIAL; + } else { + return !a014na(var4, var3) ? StringConstants.CREATE_ALERT_PASS_LENGTH : StringConstants.CREATE_ALERT_PASS_CONTAINS_NAME; + } + } else { + return StringConstants.PASSWORD_IS_VALID; + } + } +} diff --git a/src/main/java/funorb/commonui/form/validator/StringValidator.java b/src/main/java/funorb/commonui/form/validator/StringValidator.java new file mode 100644 index 0000000..8ca26d7 --- /dev/null +++ b/src/main/java/funorb/commonui/form/validator/StringValidator.java @@ -0,0 +1,40 @@ +package funorb.commonui.form.validator; + +import funorb.commonui.AbstractTextField; +import funorb.commonui.listener.TextFieldListener; + +public abstract class StringValidator extends AbstractInputValidator implements TextFieldListener { + private final AbstractTextField _i; + + protected StringValidator(final AbstractTextField var1) { + this._i = var1; + } + + @Override + public final boolean a154() { + return this._i.text == null || this._i.text.length() == 0; + } + + @Override + public final ValidationState a083() { + return this.b492(this._i.text); + } + + protected abstract ValidationState b492(String var2); + + protected abstract String a751(String var2); + + @Override + public final void handleTextFieldEnterPressed(final AbstractTextField textField) { + } + + @Override + public final void handleTextFieldChanged() { + this.b150(); + } + + @Override + public final String c983() { + return this.a751(this._i.text); + } +} diff --git a/src/main/java/funorb/commonui/form/validator/UsernameValidator.java b/src/main/java/funorb/commonui/form/validator/UsernameValidator.java new file mode 100644 index 0000000..c67d742 --- /dev/null +++ b/src/main/java/funorb/commonui/form/validator/UsernameValidator.java @@ -0,0 +1,185 @@ +package funorb.commonui.form.validator; + +import funorb.Strings; +import funorb.commonui.CommonUI; +import funorb.commonui.Enum1; +import funorb.commonui.AbstractTextField; +import funorb.commonui.kj_; +import funorb.shatteredplans.StringConstants; + +import java.util.stream.IntStream; + +public final class UsernameValidator extends StringValidator { + public static kj_ _ija; + public static String _gpb; + private String _n; + private boolean _o = false; + + public UsernameValidator(final AbstractTextField var1) { + super(var1); + } + + private static String a150nn(final CharSequence var0) { + final String var2 = a615wp(var0); + if (var2 == null) { + for (int var4 = 0; var0.length() > var4; ++var4) { + if (!isAllowedInUsername(var0.charAt(var4))) { + return StringConstants.CREATE_ALERT_NAME_CHARS; + } + } + + return null; + } else { + return var2; + } + } + + private static boolean isValidUsername(final CharSequence var0) { + if (!isValidUsername(var0, false)) { + return false; + } + return IntStream.range(0, var0.length()).allMatch(i -> isAllowedInUsername(var0.charAt(i))); + } + + public static boolean isValidUsername(final CharSequence str, final boolean allowConsecutiveSpaceLikeChars) { + // usernames must be between 1 and 12 characters + if (str == null || str.length() < 1 || str.length() > 12) { + return false; + } + + final String normalized = Strings.normalize(str); + if (normalized == null || normalized.length() < 1) { + return false; + } + if (Strings.isSpaceLikeUsernameChar(normalized.charAt(0)) || Strings.isSpaceLikeUsernameChar(normalized.charAt(normalized.length() - 1))) { + return false; + } + + if (!allowConsecutiveSpaceLikeChars) { + int consecutiveSpaceLikeChars = 0; + for (int i = 0; i < str.length(); ++i) { + final char c = str.charAt(i); + if (Strings.isSpaceLikeUsernameChar(c)) { + ++consecutiveSpaceLikeChars; + } else { + consecutiveSpaceLikeChars = 0; + } + + if (consecutiveSpaceLikeChars >= 2) { + return false; + } + } + } + + return true; + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + private static boolean isAllowedInUsername(final char var0) { + if (Character.isISOControl(var0)) { + return false; + } else if (Strings.isAlphanumeric(var0)) { + return true; + } else { + return var0 == '-' || var0 == Strings.NON_BREAKING_SPACE || var0 == ' ' || var0 == '_'; + } + } + + private static kj_ a382ji(final String var1) { + if (CommonUI._fjs == Enum1.C3) { + return null; + } else if (CommonUI._fjs == Enum1.C2 && var1.equals(_gpb)) { + CommonUI._fjs = Enum1.C1; + return _ija; + } else { + _gpb = var1; + _ija = null; + CommonUI._fjs = Enum1.C3; + return null; + } + } + + private static String a615wp(final CharSequence var0) { + if (var0 == null) { + return StringConstants.CREATE_ALERT_NAME_LENGTH; + } else { + final int var2 = var0.length(); + if (var2 >= 1 && var2 <= 12) { + final String var3 = Strings.normalize(var0); + if (var3 != null && var3.length() >= 1) { + if (Strings.isSpaceLikeUsernameChar(var3.charAt(0)) || Strings.isSpaceLikeUsernameChar(var3.charAt(var3.length() - 1))) { + return StringConstants.CREATE_ALERT_NAME_LEADING_SPACE; + } else { + int var4 = 0; + + for (int var5 = 0; var0.length() > var5; ++var5) { + final char var6 = var0.charAt(var5); + if (Strings.isSpaceLikeUsernameChar(var6)) { + ++var4; + } else { + var4 = 0; + } + + if (var4 >= 2) { + return StringConstants.CREATE_ALERT_DOUBLE_SPACE; + } + } + + if (var4 > 0) { + return StringConstants.CREATE_ALERT_NAME_LEADING_SPACE; + } else { + return null; + } + } + } else { + return StringConstants.CREATE_ALERT_NAME_LENGTH; + } + } else { + return StringConstants.CREATE_ALERT_NAME_LENGTH; + } + } + } + + @Override + public ValidationState b492(final String username) { + if (!isValidUsername(username)) { + return ValidationState.INVALID; + } + + if (!username.equals(this._n)) { + final kj_ var3 = a382ji(username); + if (var3 == null || var3._g != null) { + return ValidationState.CHECKING_1; + } + + this._o = var3._h; + this._n = username; + } + + return this._o ? ValidationState.C2 : ValidationState.INVALID; + } + + public void d150() { + this._n = null; + } + + @Override + public String a751(final String var2) { + final String var3 = a150nn(var2); + if (var3 == null) { + if (!var2.equals(this._n)) { + final kj_ var4 = a382ji(var2); + if (var4 == null || var4._g != null) { + return null; + } + + this._n = var2; + this._o = var4._h; + } + + return !this._o ? StringConstants.CREATE_USERNAME_UNAVAILABLE : StringConstants.CREATE_USERNAME_AVAILABLE; + } else { + return var3; + } + } +} diff --git a/src/main/java/funorb/commonui/form/validator/ValidationState.java b/src/main/java/funorb/commonui/form/validator/ValidationState.java new file mode 100644 index 0000000..c7d3c41 --- /dev/null +++ b/src/main/java/funorb/commonui/form/validator/ValidationState.java @@ -0,0 +1,5 @@ +package funorb.commonui.form.validator; + +public enum ValidationState { + CHECKING_1, C2, CHECKING_2, INVALID, C5 +} diff --git a/src/main/java/funorb/commonui/g_.java b/src/main/java/funorb/commonui/g_.java new file mode 100644 index 0000000..883bcf4 --- /dev/null +++ b/src/main/java/funorb/commonui/g_.java @@ -0,0 +1,4 @@ +package funorb.commonui; + +public interface g_ { +} diff --git a/src/main/java/funorb/commonui/hl_.java b/src/main/java/funorb/commonui/hl_.java new file mode 100644 index 0000000..d194317 --- /dev/null +++ b/src/main/java/funorb/commonui/hl_.java @@ -0,0 +1,63 @@ +package funorb.commonui; + +import funorb.commonui.form.validator.InputValidator; +import funorb.commonui.form.validator.ValidationState; +import funorb.graphics.Drawing; +import funorb.graphics.Sprite; + +public final class hl_ extends Button { + private static Sprite _gge; + private final InputValidator _G; + private int _F; + + public hl_(final InputValidator var1) { + this._G = var1; + } + + @Override + public String getCurrentTooltip() { + return this.isMouseOver ? this._G.a983() : null; + } + + @Override + public boolean focus(final Component previouslyFocused) { + return false; + } + + @Override + public void tick(final int x, final int y, final Component root) { + ++this._F; + super.tick(x, y, root); + } + + @Override + public void draw(final int x, final int y) { + super.draw(x, y); + final int var5 = (this.width >> 1) + x + this.x; + final int var6 = (this.height >> 1) + y + this.y; + final ValidationState var8 = this._G.validate(); + final Sprite var7; + if (var8 == ValidationState.CHECKING_2 || var8 == ValidationState.CHECKING_1) { + var7 = Resources.VALIDATION[0]; + final int var9 = var7.offsetX << 1; + final int var10 = var7.offsetY << 1; + if (_gge != null && var9 <= _gge.width && _gge.height >= var10) { + _gge.withInstalledForDrawingUsingOffsets(() -> { + Drawing.clear(); + var7.b669(112, 144, var7.offsetX << 4, var7.offsetY << 4, -this._F << 10, 4096); + }); + } else { + _gge = new Sprite(var9, var10); + _gge.withInstalledForDrawingUsingOffsets(() -> + var7.b669(112, 144, var7.offsetX << 4, var7.offsetY << 4, -this._F << 10, 4096)); + } + _gge.drawAdd(var5 - var7.offsetX, -var7.offsetY + var6, 256); + } else if (var8 == ValidationState.INVALID) { + var7 = Resources.VALIDATION[2]; + var7.drawAdd(-(var7.width >> 1) + var5, var6 - (var7.height >> 1), 256); + } else if (var8 == ValidationState.C2) { + var7 = Resources.VALIDATION[1]; + var7.drawAdd(-(var7.width >> 1) + var5, -(var7.height >> 1) + var6, 256); + } + } +} diff --git a/src/main/java/funorb/commonui/kj_.java b/src/main/java/funorb/commonui/kj_.java new file mode 100644 index 0000000..6fea127 --- /dev/null +++ b/src/main/java/funorb/commonui/kj_.java @@ -0,0 +1,13 @@ +package funorb.commonui; + +public final class kj_ { + public final boolean _h; + public boolean _b; + public String[] _d; + public int _c; + public String _g; + + public kj_(final boolean var1) { + this._h = var1; + } +} diff --git a/src/main/java/funorb/commonui/ks_.java b/src/main/java/funorb/commonui/ks_.java new file mode 100644 index 0000000..e6ba11a --- /dev/null +++ b/src/main/java/funorb/commonui/ks_.java @@ -0,0 +1,28 @@ +package funorb.commonui; + +public final class ks_ { + private final String _f; + private boolean _d = false; + private boolean _g = false; + + public ks_(final String var1) { + this._f = var1; + } + + public boolean b154() { + return this._g; + } + + public void a540(final boolean var1) { + this._g = true; + this._d = var1; + } + + public boolean a491() { + return this._d; + } + + public String a738() { + return this._f; + } +} diff --git a/src/main/java/funorb/commonui/listener/ButtonListener.java b/src/main/java/funorb/commonui/listener/ButtonListener.java new file mode 100644 index 0000000..369e2ab --- /dev/null +++ b/src/main/java/funorb/commonui/listener/ButtonListener.java @@ -0,0 +1,7 @@ +package funorb.commonui.listener; + +import funorb.commonui.Button; + +public non-sealed interface ButtonListener extends ComponentListener { + void handleButtonClicked(Button button); +} diff --git a/src/main/java/funorb/commonui/listener/ComponentListener.java b/src/main/java/funorb/commonui/listener/ComponentListener.java new file mode 100644 index 0000000..91fbb95 --- /dev/null +++ b/src/main/java/funorb/commonui/listener/ComponentListener.java @@ -0,0 +1,4 @@ +package funorb.commonui.listener; + +public sealed interface ComponentListener permits ButtonListener, TextFieldListener { +} diff --git a/src/main/java/funorb/commonui/listener/TextFieldListener.java b/src/main/java/funorb/commonui/listener/TextFieldListener.java new file mode 100644 index 0000000..78e75c9 --- /dev/null +++ b/src/main/java/funorb/commonui/listener/TextFieldListener.java @@ -0,0 +1,8 @@ +package funorb.commonui.listener; + +import funorb.commonui.AbstractTextField; + +public non-sealed interface TextFieldListener extends ComponentListener { + void handleTextFieldChanged(); + void handleTextFieldEnterPressed(AbstractTextField textField); +} diff --git a/src/main/java/funorb/commonui/op_.java b/src/main/java/funorb/commonui/op_.java new file mode 100644 index 0000000..b70e2d0 --- /dev/null +++ b/src/main/java/funorb/commonui/op_.java @@ -0,0 +1,5 @@ +package funorb.commonui; + +public interface op_ { + void a746(int var2); +} diff --git a/src/main/java/funorb/commonui/pe_.java b/src/main/java/funorb/commonui/pe_.java new file mode 100644 index 0000000..9ff962e --- /dev/null +++ b/src/main/java/funorb/commonui/pe_.java @@ -0,0 +1,71 @@ +package funorb.commonui; + +import funorb.Strings; +import funorb.awt.KeyState; +import funorb.commonui.container.ListContainer; +import funorb.commonui.form.CreateAccountForm; +import funorb.commonui.listener.ButtonListener; +import funorb.commonui.renderer.TextRenderer; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.shatteredplans.StringConstants; + +public final class pe_ extends ListContainer implements op_, ButtonListener { + private final Button _H; + private final CreateAccountPage _I; + + public pe_(final CreateAccountPage var1) { + super(0, 0, 288, 0); + this._I = var1; + this._H = new Button(StringConstants.CONT, null); + final String var2 = Strings.format(StringConstants.CREATE_U13_TERMS, "", "
"); + final byte var3 = 20; + final TextRenderer var4 = new TextRenderer(Resources.AREZZO_14, 0, 0, 0, 0, Drawing.WHITE, Font.HorizontalAlignment.JUSTIFY, Font.VerticalAlignment.TOP, Resources.AREZZO_14.ascent, true); + final ts_ _G = new ts_(var2, var4); + _G.tooltip = ""; + _G.a096(0, StringConstants.OPEN_IN_POPUP_WINDOW); + _G.a096(1, StringConstants.OPEN_IN_POPUP_WINDOW); + _G.listener = this; + _G.width = this.width - 40; + _G.a652(26, var3, this.width - 40); + final int var7 = var3 + _G.height + 15; + this.addChild(_G); + final byte var5 = 4; + final short var6 = 200; + this._H.setBounds(50, var7, var6, 40); + this._H.listener = this; + this.addChild(this._H); + this.setBounds(0, 0, 300, var7 + 55 + var5); + } + + @Override + public void a746(final int var2) { + if (var2 == 0) { + CreateAccountForm.a984gm("terms.ws"); + } else if (var2 == 1) { + CreateAccountForm.a984gm("privacy.ws"); + } else if (var2 == 2) { + CreateAccountForm.a984gm("conduct.ws"); + } + } + + @Override + public boolean a686(final int keyCode, final char keyChar, final Component var4) { + if (super.a686(keyCode, keyChar, var4)) { + return true; + } else if (keyCode == KeyState.Code.UP) { + return this.a611(var4); + } else { + return keyCode == KeyState.Code.DOWN && this.a948(var4); + } + } + + @Override + public void handleButtonClicked(final Button button) { + if (button == this._H) { + CreateAccountPage.b150rm(); + this._I.i423(); + } + + } +} diff --git a/src/main/java/funorb/commonui/pg_.java b/src/main/java/funorb/commonui/pg_.java new file mode 100644 index 0000000..99e02dd --- /dev/null +++ b/src/main/java/funorb/commonui/pg_.java @@ -0,0 +1,61 @@ +package funorb.commonui; + +import funorb.commonui.container.WrapperContainer; +import funorb.graphics.Font; + +public final class pg_ extends WrapperContainer { + private final int _K; + private final int _H; + private final boolean _I; + private final Font _G; + private final String _L; + private final int _D; + + public pg_(final int var1, final int var2, final int var3, final Component var5, final boolean var6, final int var7, final int var8, final Font var9, final int var10, final String var11) { + super(var1, var2, var3, 25); + this.child = var5; + this._L = var11; + this._D = var10; + this._H = var7; + this._G = var9; + this._K = var8; + this._I = var6; + final int var12 = -this._K + this._H; + int var13 = this._G.measureParagraphHeight(var11, var12, this._G.ascent) + this._K * 2; + if (var13 <= 25) { + var13 = 25; + } else { + this.setBounds(var1, var2, var3, var13); + } + + final int var14 = this._I ? 0 : 2 * this._K + this._H; + this.child.setBounds(var14, (-25 + var13 >> 1) + this._K, -this._H + var3 - 3 * this._K, 25 - 2 * this._K); + } + + @Override + public String getCurrentTooltip() { + final boolean var2 = this.child.isMouseOver; + this.child.isMouseOver = this.isMouseOver; + final String var3 = this.child.getCurrentTooltip(); + this.child.isMouseOver = var2; + return var3; + } + + @Override + public void draw(final int x, final int y) { + final int var5 = this.x + x; + final int var6 = this.y + y; + super.draw(x, y); + final int var7 = !this._I ? 0 : -(2 * this._K) - this._H + this.width; + this._G.drawParagraph( + this._L, + var5 + var7 + this._K, + var6 + this._K, + this._H - this._K, + this.height - this._K * 2, + this._D, + this._I ? Font.HorizontalAlignment.LEFT : Font.HorizontalAlignment.RIGHT, + Font.VerticalAlignment.MIDDLE, + this._G.ascent); + } +} diff --git a/src/main/java/funorb/commonui/ql_.java b/src/main/java/funorb/commonui/ql_.java new file mode 100644 index 0000000..f7a0f10 --- /dev/null +++ b/src/main/java/funorb/commonui/ql_.java @@ -0,0 +1,18 @@ +package funorb.commonui; + +public final class ql_ { + public final int _l; + public final int _m; + public final int _k; + public final int _i; + public final int _j; + public ql_ _h; + + public ql_(final int var1, final int var2, final int var3, final int var4, final int var5) { + this._m = var3; + this._j = var4; + this._l = var5; + this._i = var1; + this._k = var2; + } +} diff --git a/src/main/java/funorb/commonui/renderer/ButtonRenderer.java b/src/main/java/funorb/commonui/renderer/ButtonRenderer.java new file mode 100644 index 0000000..5baeca3 --- /dev/null +++ b/src/main/java/funorb/commonui/renderer/ButtonRenderer.java @@ -0,0 +1,49 @@ +package funorb.commonui.renderer; + +import funorb.commonui.Button; +import funorb.commonui.Component; +import funorb.commonui.Resources; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.graphics.Sprite; + +public final class ButtonRenderer extends TextRenderer { + public static Sprite[] SPRITES; + + private static final int _y = 0x2164a2; + private static final int _u = 9543; + private static final int _x = 0x2789f5; + + public ButtonRenderer() { + this.font = Resources.AREZZO_14_BOLD; + } + + @Override + public void draw(final Component component, final int x, final int y, boolean enabled) { + final boolean var6 = component.isMouseOver || component.isFocused(); + if (component instanceof Button) { + enabled &= ((Button) component).enabled; + } + + final int var7 = !enabled ? _u : (!var6 ? _y : _x); + final int var41 = component.x + x; + if (SPRITES != null && component.width > 0) { + final int var61 = SPRITES[0].offsetX; + final int var71 = SPRITES[2].offsetX; + final int var81 = SPRITES[1].offsetX; + SPRITES[0].drawTinted(var41, y + component.y + (component.height - SPRITES[0].offsetY >> 1), var7); + SPRITES[2].drawTinted(-var71 + var41 + component.width, y + component.y + (component.height - SPRITES[0].offsetY >> 1), var7); + Drawing.withSavedBounds(() -> { + Drawing.expandBoundsToInclude(var61 + var41, y + component.y + (component.height - SPRITES[0].offsetY >> 1), var41 + (component.width - var71), SPRITES[1].offsetY + y + component.y + (component.height - SPRITES[0].offsetY >> 1)); + final int var9 = var41 + var61; + final int var10 = component.width + var41 - var71; + + for (int var42 = var9; var42 < var10; var42 += var81) { + SPRITES[1].drawTinted(var42, y + component.y + (component.height - SPRITES[0].offsetY >> 1), var7); + } + }); + } + final int var8 = !enabled ? 7105644 : Drawing.WHITE; + this.font.drawParagraph(component.text, x + component.x, component.y - 2 + y, component.width, component.height, var8, Font.HorizontalAlignment.CENTER, Font.VerticalAlignment.MIDDLE, this.font.ascent); + } +} diff --git a/src/main/java/funorb/commonui/renderer/CheckboxRenderer.java b/src/main/java/funorb/commonui/renderer/CheckboxRenderer.java new file mode 100644 index 0000000..2f0ea22 --- /dev/null +++ b/src/main/java/funorb/commonui/renderer/CheckboxRenderer.java @@ -0,0 +1,23 @@ +package funorb.commonui.renderer; + +import funorb.commonui.Button; +import funorb.commonui.Component; +import funorb.commonui.Resources; +import funorb.graphics.Sprite; + +public final class CheckboxRenderer implements ComponentRenderer { + @Override + public void draw(final Component component, final int x, final int y, final boolean enabled) { + final int x1 = x + component.x; + final int y1 = y + component.y; + ComponentRenderer.drawGradientOutline(x1, y1, component.width, component.height); + final Sprite var8 = Resources.VALIDATION[1]; + if (component instanceof Button && ((Button) component).active) { + var8.drawAdd(1 + x1 + (component.width - var8.offsetX >> 1), (-var8.offsetY + component.height >> 1) + 1 + y1, 256); + } + + if (component.isFocused()) { + Button.drawFocusRect(x1 + 2, y1 + 2, component.width - 4, component.height - 4); + } + } +} diff --git a/src/main/java/funorb/commonui/renderer/ComponentRenderer.java b/src/main/java/funorb/commonui/renderer/ComponentRenderer.java new file mode 100644 index 0000000..467395d --- /dev/null +++ b/src/main/java/funorb/commonui/renderer/ComponentRenderer.java @@ -0,0 +1,22 @@ +package funorb.commonui.renderer; + +import funorb.commonui.Component; +import funorb.graphics.Drawing; + +public interface ComponentRenderer { + static void drawGradientOutline(final int x, final int y, final int width, final int height) { + Drawing.horizontalLine(x, y, width + 1, 0x989898); + Drawing.horizontalLine(x, y + height, width + 1, 0xb8b8b8); + final int y1 = Math.max(1, Drawing.top - y); + final int y2 = Math.min(height, Drawing.bottom - y); + for (int i = y1; i < y2; ++i) { + final int gray = ((i * 0x30) / height) + 0x98; + final int color = Drawing.gray(gray); + final int n = Drawing.width * (i + y) + x; + Drawing.screenBuffer[n] = color; + Drawing.screenBuffer[n + width] = color; + } + } + + void draw(Component component, int x, int y, boolean enabled); +} diff --git a/src/main/java/funorb/commonui/renderer/ITextRenderer.java b/src/main/java/funorb/commonui/renderer/ITextRenderer.java new file mode 100644 index 0000000..78d018a --- /dev/null +++ b/src/main/java/funorb/commonui/renderer/ITextRenderer.java @@ -0,0 +1,26 @@ +package funorb.commonui.renderer; + +import funorb.commonui.Component; +import funorb.commonui.AbstractTextLayout; + +public interface ITextRenderer extends ComponentRenderer { + AbstractTextLayout updateLayout(Component component); + + int a242(int var1, int var2, int var3, Component var4, int var6); + + int getPreferredHeight(Component component); + + int getAvailableWidth(Component component); + + int a474(); + + void a132(int var1, int var2, int var3, int var4, Component var6); + + int b754(Component var2, int var3); + + int getPreferredWidth(Component component); + + void a403(int var1, int var2, int var4, Component var5); + + int a754(int var1, Component var2); +} diff --git a/src/main/java/funorb/commonui/renderer/LinkRenderer.java b/src/main/java/funorb/commonui/renderer/LinkRenderer.java new file mode 100644 index 0000000..5fb0195 --- /dev/null +++ b/src/main/java/funorb/commonui/renderer/LinkRenderer.java @@ -0,0 +1,51 @@ +package funorb.commonui.renderer; + +import funorb.commonui.Button; +import funorb.commonui.Component; +import funorb.commonui.Resources; +import funorb.graphics.Font; +import org.jetbrains.annotations.NotNull; + +public final class LinkRenderer implements ComponentRenderer { + private final Font font; + private final @NotNull Font.HorizontalAlignment horizontalAlignment; + private final @NotNull Font.VerticalAlignment verticalAlignment; + + public LinkRenderer() { + this.font = Resources.AREZZO_14; + this.horizontalAlignment = Font.HorizontalAlignment.CENTER; + this.verticalAlignment = Font.VerticalAlignment.MIDDLE; + } + + public LinkRenderer(final Font var1) { + this.font = var1; + this.horizontalAlignment = Font.HorizontalAlignment.LEFT; + this.verticalAlignment = Font.VerticalAlignment.MIDDLE; + } + + @Override + public void draw(final Component component, final int x, final int y, final boolean enabled) { + final int var6 = !component.isMouseOver && !component.isFocused() ? 2188450 : 3249872; + this.font.drawParagraph("" + component.text + "
", x + component.x, y + component.y, component.width, component.height, var6, this.horizontalAlignment, this.verticalAlignment, this.font.descent + this.font.ascent); + if (component.isFocused()) { + final int var7 = this.font.measureLineWidth(component.text); + final int var8 = this.font.ascent + this.font.descent; + int var9 = component.x + x; + if (this.horizontalAlignment == Font.HorizontalAlignment.RIGHT) { + var9 += -var7 + component.width; + } else if (this.horizontalAlignment == Font.HorizontalAlignment.CENTER) { + var9 += -var7 + component.width >> 1; + } + + int var10 = component.y + y; + if (this.verticalAlignment == Font.VerticalAlignment.BOTTOM) { + var10 += component.height - var8; + } else if (this.verticalAlignment == Font.VerticalAlignment.MIDDLE) { + var10 += -var8 + component.height >> 1; + } + + Button.drawFocusRect(var9 - 2, var10 + 2, var7 + 4, var8); + } + + } +} diff --git a/src/main/java/funorb/commonui/renderer/PasswordFieldRenderer.java b/src/main/java/funorb/commonui/renderer/PasswordFieldRenderer.java new file mode 100644 index 0000000..31a23c2 --- /dev/null +++ b/src/main/java/funorb/commonui/renderer/PasswordFieldRenderer.java @@ -0,0 +1,27 @@ +package funorb.commonui.renderer; + +import funorb.commonui.Component; +import funorb.commonui.Resources; +import funorb.graphics.Font; + +public final class PasswordFieldRenderer extends TextFieldRenderer { + private PasswordFieldRenderer(final Font font) { + super(font); + } + + public PasswordFieldRenderer() { + this(Resources.AREZZO_14); + } + + @Override + protected String getText(final Component component) { + final int var1 = component.text.length(); + final char[] var21 = new char[var1]; + + for (int var3 = 0; var3 < var1; ++var3) { + var21[var3] = '*'; + } + + return new String(var21); + } +} diff --git a/src/main/java/funorb/commonui/renderer/TextFieldRenderer.java b/src/main/java/funorb/commonui/renderer/TextFieldRenderer.java new file mode 100644 index 0000000..d7497a3 --- /dev/null +++ b/src/main/java/funorb/commonui/renderer/TextFieldRenderer.java @@ -0,0 +1,23 @@ +package funorb.commonui.renderer; + +import funorb.commonui.Component; +import funorb.commonui.Resources; +import funorb.graphics.Font; + +public class TextFieldRenderer extends TextRenderer { + protected TextFieldRenderer(final Font font) { + super(font, 4, 2, 2, 2, 10000536, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.MIDDLE, font.ascent, false); + } + + public TextFieldRenderer() { + this(Resources.AREZZO_14); + } + + @Override + public final void draw(final Component component, final int x, final int y, final boolean enabled) { + if (enabled) { + ComponentRenderer.drawGradientOutline(x + component.x, component.y + y, component.width, component.height); + } + super.draw(component, x, y, enabled); + } +} diff --git a/src/main/java/funorb/commonui/renderer/TextRenderer.java b/src/main/java/funorb/commonui/renderer/TextRenderer.java new file mode 100644 index 0000000..4f966cf --- /dev/null +++ b/src/main/java/funorb/commonui/renderer/TextRenderer.java @@ -0,0 +1,235 @@ +package funorb.commonui.renderer; + +import funorb.commonui.AbstractTextLayout; +import funorb.commonui.Component; +import funorb.commonui.TextLayout; +import funorb.commonui.TextLineMetrics; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import org.jetbrains.annotations.NotNull; + +public class TextRenderer implements ITextRenderer { + protected Font font; + private final int _p; + private final int _o; + private final int _b; + private final int _g; + private final int _f; + private final int _e; + private final @NotNull Font.HorizontalAlignment horizontalAlignment; + private final @NotNull Font.VerticalAlignment verticalAlignment; + private final int leading; + private final boolean isMultiline; + + protected TextRenderer() { + this(null, 0, 0, 0, 0, 0, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, 0, false); + } + + public TextRenderer(final Font font, + final int _o, + final int _g, + final int _b, + final int _f, + final int _p, + final @NotNull Font.HorizontalAlignment horizontalAlignment, + final @NotNull Font.VerticalAlignment verticalAlignment, + final int leading, + final boolean isMultiline) { + this.font = font; + this._o = _o; + this._g = _g; + this._b = _b; + this._f = _f; + this._p = _p; + this.horizontalAlignment = horizontalAlignment; + this.verticalAlignment = verticalAlignment; + this.leading = leading; + this.isMultiline = isMultiline; + this._e = Integer.MAX_VALUE; + } + + @Override + public final int getPreferredWidth(final Component component) { + this.updateLayout(component); + return component.textLayout.getWidth() - (this._g + this._o); + } + + @Override + public final void a403(final int var1, final int var2, final int var4, final Component var5) { + if (var5.isFocused()) { + final AbstractTextLayout var6 = this.updateLayout(var5); + final int var7 = var6.a543(var1); + final TextLineMetrics var8 = var6.lineMetrics[var7]; + final int var9 = var6.a527(var1); + final int var10 = this.b896(var5, var9, var2); + final int var11 = this.a754(var4, var5) + Math.max(0, var8.top); + final int var12 = this.a754(var4, var5) + Math.min(this.getAvailableHeight(var5), Math.min(var8.bottom, var6.lineMetrics.length > 1 + var7 ? var6.lineMetrics[1 + var7].top : var8.bottom)); + Drawing.withLocalContext(() -> { + Drawing.expandBoundsToInclude(var2 + var5.x, var5.y + var4, var5.width + var2 + var5.x, var5.height + var5.y + var4); + Drawing.line(var10, var11, var10, var12, -1); + }); + } + } + + @Override + public final AbstractTextLayout updateLayout(final Component component) { + if (component.textLayout == null) { + component.textLayout = new TextLayout(); + } + if (this.isMultiline) { + component.textLayout.layoutParagraph( + this.font, + this.getText(component), + this.horizontalAlignment, + this.verticalAlignment, + this.getAvailableWidth(component), + this.getAvailableHeight(component), + this.leading); + } else { + this.updateLayoutSingleLine(component); + } + return component.textLayout; + } + + @Override + public final int a242(final int var1, final int var2, final int var3, final Component var4, final int var6) { + this.updateLayout(var4); + return var4.textLayout.a313(-this.b754(var4, var1) + var2, var6 - this.a754(var3, var4)); + } + + private int a896(final Component var2, final int var4) { + return var2._l + this._b + var2.y + var4; + } + + @Override + public final void a132(final int var1, final int var2, final int var3, final int var4, final Component var6) { + if (var1 != var4) { + if (var6.isFocused()) { + final AbstractTextLayout var7 = this.updateLayout(var6); + final int var8; + final int var9; + if (var1 >= var4) { + var9 = var1; + var8 = var4; + } else { + var8 = var1; + var9 = var4; + } + + final int var10 = var7.a543(var8); + final int var11 = var7.a543(var9); + Drawing.withLocalContext(() -> { + Drawing.expandBoundsToInclude(var3 + var6.x, var2 + var6.y, var3 + var6.x + var6.width, var2 + var6.y + var6.height); + for (int var12 = var10; var11 >= var12; ++var12) { + final TextLineMetrics var13 = var7.lineMetrics[var12]; + assert var13 != null; + final int var14 = var12 == var10 ? var7.a527(var8) : var13._b[0]; + final int var15 = var12 != var11 ? var13._b[var13.getCharCount()] : var7.a527(var9); + Drawing.fillRect(this.b896(var6, var14, var3), var13.top + var2 + var6.y + this._b + var6._l, var15 - var14, var13.bottom, this._e, this._e >>> 24); + } + }); + } + } + } + + @Override + public final int a754(final int var1, final Component var2) { + return this.a896(var2, var1); + } + + @Override + public final int b754(final Component var2, final int var3) { + return this.b896(var2, 0, var3); + } + + protected String getText(final Component component) { + return component.text; + } + + @Override + public final int getAvailableWidth(final Component component) { + return component.width - this._o - this._g; + } + + @Override + public final int getPreferredHeight(final Component component) { + this.updateLayout(component); + return component.textLayout.b137() + this._b + this._f; + } + + private void updateLayoutSingleLine(final Component component) { + if (component.textLayout == null) { + component.textLayout = new TextLayout(); + } + + final int var3 = this.getAvailableWidth(component); + final int var4 = this.getAvailableHeight(component); + final int var5; + if (this.verticalAlignment == Font.VerticalAlignment.TOP) { + var5 = this.font.ascent; + } else if (this.verticalAlignment == Font.VerticalAlignment.BOTTOM) { + var5 = var4 - this.font.descent; + } else { + var5 = ((var4 - this.font.ascent - this.font.descent) / 2) + this.font.ascent; + } + + if (this.horizontalAlignment == Font.HorizontalAlignment.LEFT || this.horizontalAlignment == Font.HorizontalAlignment.JUSTIFY) { + component.textLayout.layoutLineAlignedLeft(this.font, this.getText(component), var5); + } else if (this.horizontalAlignment == Font.HorizontalAlignment.CENTER) { + component.textLayout.layoutLineCentered(var5, this.getText(component), this.font, var3 / 2); + } else if (this.horizontalAlignment == Font.HorizontalAlignment.RIGHT) { + component.textLayout.layoutLineAlignedRight(var5, this.font, this.getText(component), var3); + } + } + + private void a768(final int var1, final int var2, final int var3, final Component var5) { + Drawing.withLocalContext(() -> { + Drawing.expandBoundsToInclude(var1 + var5.x, var5.y + var2, var5.x + var1 + var5.width, var5.y + var2 + var5.height); + final int var9 = this.getAvailableWidth(var5); + final int var10 = this.getAvailableHeight(var5); + if (this.isMultiline) { + this.font.drawParagraph(this.getText(var5), this.b896(var5, 0, var1), this.a896(var5, var2), var9, var10, var3, this.horizontalAlignment, this.verticalAlignment, this.leading); + } else { + final Font.VerticalAlignment var12 = this.verticalAlignment; + final int var11; + if (var12 == Font.VerticalAlignment.TOP) { + var11 = this.font.ascent; + } else if (var12 == Font.VerticalAlignment.BOTTOM) { + var11 = -this.font.descent + var10; + } else { + var11 = (-this.font.descent - this.font.ascent + var10 >> 1) + this.font.ascent; + } + + final Font.HorizontalAlignment r = this.horizontalAlignment; + if (r == Font.HorizontalAlignment.LEFT || r == Font.HorizontalAlignment.JUSTIFY) { + this.font.draw(this.getText(var5), this.b896(var5, 0, var1), var11 + this.a896(var5, var2), var3); + } else if (r == Font.HorizontalAlignment.CENTER) { + this.font.drawCentered(this.getText(var5), (var9 >> 1) + this.b896(var5, 0, var1), var11 + this.a896(var5, var2), var3); + } else if (r == Font.HorizontalAlignment.RIGHT) { + this.font.drawRightAligned(this.getText(var5), var9 + this.b896(var5, 0, var1), this.a896(var5, var2) + var11, var3); + } + } + }); + } + + private int b896(final Component var2, final int var3, final int var4) { + return var3 + this._o + var2.x + var4 + var2._h; + } + + @Override + public final int a474() { + + return this.font.descent + this.font.ascent; + } + + private int getAvailableHeight(final Component var1) { + return var1.height - this._f - this._b; + } + + @Override + public void draw(final Component component, final int x, final int y, final boolean enabled) { + if (this.font != null) { + this.a768(x, y, this._p, component); + } + } +} diff --git a/src/main/java/funorb/commonui/ts_.java b/src/main/java/funorb/commonui/ts_.java new file mode 100644 index 0000000..e362f88 --- /dev/null +++ b/src/main/java/funorb/commonui/ts_.java @@ -0,0 +1,148 @@ +package funorb.commonui; + +import funorb.commonui.renderer.ComponentRenderer; +import funorb.commonui.renderer.ITextRenderer; +import funorb.shatteredplans.client.JagexApplet; + +import java.util.ArrayList; +import java.util.List; + +public class ts_ extends Button { + private List _D; + private ql_ _I = null; + private String[] _J; + + public ts_(final String text, final ComponentRenderer renderer) { + super(text, renderer, null); + } + + @Override + public void draw(final int x, final int y) { + super.draw(x, y); + final ITextRenderer var5 = (ITextRenderer) this.renderer; + ql_ var6 = this._I; + if (var6 != null) { + final int var7 = var5.b754(this, x); + final int var8 = var5.a754(y, this); + + do { + Button.drawFocusRect(var6._k + var7 - 2, var8 + (var6._m - 2), 2 + var6._j, 2 + var6._l); + var6 = var6._h; + } while (var6 != null); + } + } + + public final void a096(final int var1, final String var3) { + if (this._J == null || this._J.length <= var1) { + final String[] var4 = new String[1 + var1]; + if (this._J != null) { + System.arraycopy(this._J, 0, var4, 0, this._J.length); + } + + this._J = var4; + } + + this._J[var1] = var3; + + } + + @Override + public final void setBounds(final int x, final int y, final int width, final int height) { + super.setBounds(x, y, width, height); + this.e487(); + } + + @Override + public boolean focus(final Component previouslyFocused) { + return false; + } + + public final void a652(final int var1, final int var2, final int var4) { + this.setBounds(var1, var2, var4, ((ITextRenderer) this.renderer).getPreferredHeight(this)); + } + + protected final void e487() { + this._D = new ArrayList<>(); + + int var2 = 0; + final ITextRenderer var3 = (ITextRenderer) this.renderer; + final AbstractTextLayout var4 = var3.updateLayout(this); + + while (true) { + final int var5 = this.text.indexOf("", var5); + final String var6 = this.text.substring(var5 + 9, var7); + final int i = Integer.parseInt(var6); + var2 = this.text.indexOf("", var5); + final int var8 = var4.a543(var5); + final int var9 = var4.a543(var2); + ql_ var10 = null; + + for (int var11 = var8; var9 >= var11; ++var11) { + final TextLineMetrics var12 = var4.lineMetrics[var11]; + final int var13 = var8 != var11 ? var12._b[0] : var4.a527(var5); + final int var14 = var11 != var9 ? (var12 == null ? 0 : var12._b[var12.getCharCount()]) : var4.a527(var2); + assert var12 != null; + final ql_ var15 = new ql_(i, var13, var12.top, var14 - var13, Math.max(var3.a474(), -var12.top + var12.bottom)); + if (var10 != null) { + var10._h = var15; + } + + var10 = var15; + this._D.add(var15); + } + } + } + + private ql_ b803(final int var1, final int var2) { + for (final ql_ var4 : this._D) { + for (ql_ var5 = var4; var5 != null; var5 = var5._h) { + if (var5._k <= var1 && var5._m <= var2 && var5._k + var5._j > var1 && var5._l + var5._m >= var2) { + return var4; + } + } + } + + return null; + } + + @Override + public String getCurrentTooltip() { + if (this._I == null || this._J == null) { + return null; + } else if (this._J.length <= this._I._i) { + return null; + } else { + + return this._J[this._I._i]; + } + } + + @Override + public void tick(final int x, final int y, final Component root) { + super.tick(x, y, root); + this._I = null; + if (this.isMouseOver) { + final int var5 = -this.x - x + JagexApplet.mouseX; + final int var6 = JagexApplet.mouseY - y - this.y; + this._I = this.b803(var5, var6); + } + + } + + @Override + public final void handleClicked(final int var1, final int var2, final int var3) { + super.handleClicked(var1, var2, var3); + final int var5 = -this.x + var2; + final int var6 = -this.y + var3; + final ql_ var7 = this.b803(var5, var6); + if (var7 != null && this.listener != null) { + ((op_) this.listener).a746(var7._i); + } + + } +} diff --git a/src/main/java/funorb/data/LRUCache.java b/src/main/java/funorb/data/LRUCache.java new file mode 100644 index 0000000..1940558 --- /dev/null +++ b/src/main/java/funorb/data/LRUCache.java @@ -0,0 +1,17 @@ +package funorb.data; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class LRUCache extends LinkedHashMap { + private static final int CAPACITY = 64; + + public LRUCache() { + super(32, 0.75F, true); + } + + @Override + protected boolean removeEldestEntry(final Map.Entry eldest) { + return this.size() > CAPACITY; + } +} diff --git a/src/main/java/funorb/data/NodeList.java b/src/main/java/funorb/data/NodeList.java new file mode 100644 index 0000000..69dcdb7 --- /dev/null +++ b/src/main/java/funorb/data/NodeList.java @@ -0,0 +1,157 @@ +package funorb.data; + +import org.jetbrains.annotations.NotNull; + +import java.util.AbstractCollection; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import static funorb.data.NodeList.Node; + +public final class NodeList extends AbstractCollection { + private final Node head; + + public NodeList() { + this.head = new Node(); + this.head.next = this.head; + this.head.prev = this.head; + } + + @Override + public boolean isEmpty() { + return this.head == this.head.next; + } + + @Override + public int size() { + int count = 0; + Node next = this.head.next; + while (next != this.head) { + count++; + next = next.next; + } + return count; + } + + @Override + public boolean add(final T node) { + this.addLast(node); + return true; + } + + public void addFirst(final T newFirst) { + newFirst.unlink(); + + final Node oldFirst = this.head.next; + this.head.next = newFirst; + newFirst.prev = this.head; + newFirst.next = oldFirst; + oldFirst.prev = newFirst; + } + + public void addLast(final T newLast) { + newLast.unlink(); + + final Node oldLast = this.head.prev; + oldLast.next = newLast; + newLast.prev = oldLast; + newLast.next = this.head; + this.head.prev = newLast; + } + + @Override + public void clear() { + Node first; + while ((first = this.head.next) != this.head) { + first.unlink(); + } + } + + @Override + public @NotNull Iterator iterator() { + return new Itr(); + } + + public @NotNull Iterator descendingIterator() { + return new DescendingItr(); + } + + public static class Node { + public Node next; + public Node prev; + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public final boolean isLinked() { + return this.prev != null; + } + + public final void unlink() { + if (this.prev != null) { + this.prev.next = this.next; + this.next.prev = this.prev; + this.prev = null; + this.next = null; + } + } + } + + private final class Itr implements Iterator { + private Node lastReturned = null; + private Node next = NodeList.this.head.next; + + @Override + public boolean hasNext() { + return this.next != NodeList.this.head; + } + + @Override + @SuppressWarnings("unchecked") + public T next() { + if (!this.hasNext()) { + throw new NoSuchElementException(); + } + final Node here = this.next; + this.next = here.next; + return (T) (this.lastReturned = here); + } + + @Override + public void remove() { + if (this.lastReturned == null) { + throw new IllegalStateException(); + } + this.lastReturned.unlink(); + this.lastReturned = null; + } + } + + private final class DescendingItr implements Iterator { + private Node lastReturned = null; + private Node next = NodeList.this.head.prev; + + @Override + public boolean hasNext() { + return this.next != NodeList.this.head; + } + + @Override + @SuppressWarnings("unchecked") + public T next() { + if (!this.hasNext()) { + throw new NoSuchElementException(); + } + final Node here = this.next; + this.next = here.prev; + return (T) (this.lastReturned = here); + } + + @Override + public void remove() { + if (this.lastReturned == null) { + throw new IllegalStateException(); + } + this.lastReturned.unlink(); + this.lastReturned = null; + } + } +} diff --git a/src/main/java/funorb/graphics/ArgbSprite.java b/src/main/java/funorb/graphics/ArgbSprite.java new file mode 100644 index 0000000..6ede076 --- /dev/null +++ b/src/main/java/funorb/graphics/ArgbSprite.java @@ -0,0 +1,1228 @@ +package funorb.graphics; + +public final class ArgbSprite extends Sprite { + public ArgbSprite(final int var1, final int var2) { + super(var1, var2); + } + + public ArgbSprite(final int var1, final int var2, final int var3, final int var4, final int var5, final int var6, final int[] var7) { + super(var1, var2, var3, var4, var5, var6, var7); + } + + private static void b057(final int[] var3, final int[] var4, int var5, int var7, final int var9, final int var10, final int var11, final int var12, final int var13) { + int var8; + for (var8 = -var10; var8 < 0; ++var8) { + int var6; + for (var6 = -var9; var6 < 0; ++var6) { + int var0 = var4[var5++]; + if (var0 == 0) { + ++var7; + } else { + final int var14 = var13 * (var0 >>> 24) >> 8 & 255; + final int var1 = (var0 & 16711935) * var14; + var0 = (var1 & -16711936) + (var0 * var14 - var1 & 16711680) >>> 8; + final int i = var3[var7]; + final int var2 = var0 + i; + var0 = (var0 & 16711935) + (i & 16711935); + final int i1 = (var0 & 16777472) + (var2 - var0 & 65536); + var3[var7++] = var2 - i1 | i1 - (i1 >>> 8); + } + } + + var7 += var11; + var5 += var12; + } + + } + + private static void b590(final int[] var0, final int[] var1, int var2, int var3, int var4, final int var5, final int var6, final int var7, final int var8, final int var9, final int var10, final int var11) { + final int var12 = var2; + + for (int var13 = -var7; var13 < 0; ++var13) { + final int var14 = (var3 >> 16) * var10; + + for (int var15 = -var6; var15 < 0; ++var15) { + final int var16 = var1[(var2 >> 16) + var14]; + final int var17 = var0[var4]; + final int var18 = (var16 >>> 24) * var11 >> 8; + final int var19 = 256 - var18; + var0[var4++] = ((var16 & 16711935) * var18 + (var17 & 16711935) * var19 & -16711936) + ((var16 & '\uff00') * var18 + (var17 & '\uff00') * var19 & 16711680) >>> 8; + var2 += var8; + } + + var3 += var9; + var2 = var12; + var4 += var5; + } + + } + + private static void d663(final int[] var0, final int[] var1, int var2, int var3, final int var4, final int var5, final int var6, final int var7, final int var8) { + for (int var9 = -var5; var9 < 0; ++var9) { + for (int var10 = -var4; var10 < 0; ++var10) { + final int var11 = (var1[var2] >>> 24) * var8 >> 8; + final int var12 = 256 - var11; + final int var13 = var1[var2++]; + final int var14 = var0[var3]; + var0[var3++] = ((var13 & 16711935) * var11 + (var14 & 16711935) * var12 & -16711936) + ((var13 & '\uff00') * var11 + (var14 & '\uff00') * var12 & 16711680) >>> 8; + } + + var3 += var6; + var2 += var7; + } + + } + + private static void d983(final int[] var0, final int[] var1, int var3, int var4, final int var7, final int var8, final int var9, final int var10, final int var11) { + final int var12 = var11 & 16711935; + final int var13 = var11 >> 8 & 255; + + int var6; + for (var6 = -var8; var6 < 0; ++var6) { + int var5; + for (var5 = -var7; var5 < 0; ++var5) { + int var2 = var1[var3++]; + final int var14 = var2 >>> 24; + var2 &= Drawing.WHITE; + if (var14 == 0) { + ++var4; + } else { + final int var18; + if (var2 >> 8 == (var2 & '\uffff')) { + var2 &= 255; + var18 = (var2 * var12 >> 8 & 16711934) + (var2 * var13 & '\uff00') + 1; + } else { + var18 = var2; + } + + final int var16 = 256 - var14; + final int var17 = var0[var4]; + var0[var4++] = ((var18 & 16711935) * var14 + (var17 & 16711935) * var16 & -16711936) + ((var18 & '\uff00') * var14 + (var17 & '\uff00') * var16 & 16711680) >>> 8; + } + } + + var4 += var9; + var3 += var10; + } + + } + + @Override + protected void compositeOver(final int[] src, final int srcStride, int srcPos, final int[] dest, final int destStride, int destPos, final int cols, final int rows) { + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + final int srcColor = src[srcPos++]; + final int alpha = srcColor >>> 24; + if (alpha == 0) { + ++destPos; + } else { + final int occlusion = 0x100 - alpha; + final int destColor = dest[destPos]; + final int rb = ((srcColor & 0xff00ff) * alpha + (destColor & 0xff00ff) * occlusion) & 0xff00ff00; + final int g = ((srcColor & 0x00ff00) * alpha + (destColor & 0x00ff00) * occlusion) & 0x00ff0000; + dest[destPos++] = (rb + g) >>> 8; + } + } + + destPos += destStride; + srcPos += srcStride; + } + } + + private static void d650(final int[] var0, final int[] var1, int var3, int var4, final int var5, final int var6, final int var7, final int var8) { + final int var9 = -var5; + + for (int var10 = -var6; var10 < 0; ++var10) { + for (int var11 = var9; var11 < 0; ++var11) { + final int var2 = var1[var3--]; + final int var12 = var2 >>> 24; + if (var12 == 0) { + ++var4; + } else { + final int var13 = 256 - var12; + final int var14 = var0[var4]; + var0[var4++] = ((var2 & 16711935) * var12 + (var14 & 16711935) * var13 & -16711936) + ((var2 & '\uff00') * var12 + (var14 & '\uff00') * var13 & 16711680) >>> 8; + } + } + + var4 += var7; + var3 += var8; + } + + } + + private static void c983(final int[] var0, final int[] var1, int var3, int var4, int var5, final int var6, final int var7, final int var8, final int var9, final int var10, final int var11) { + final int var12 = var3; + + for (int var13 = -var8; var13 < 0; ++var13) { + final int var14 = (var4 >> 16) * var11; + + for (int var15 = -var7; var15 < 0; ++var15) { + final int var2 = var1[(var3 >> 16) + var14]; + final int var16 = var2 >>> 24; + if (var16 == 0) { + ++var5; + } else { + final int var17 = 256 - var16; + final int var18 = var0[var5]; + var0[var5++] = ((var2 & 16711935) * var16 + (var18 & 16711935) * var17 & -16711936) + ((var2 & '\uff00') * var16 + (var18 & '\uff00') * var17 & 16711680) >>> 8; + } + + var3 += var9; + } + + var4 += var10; + var3 = var12; + var5 += var6; + } + + } + + private static void c663(final int[] var0, final int[] var1, int var3, int var4, int var5, final int var6, final int var7, final int var8, final int var9) { + final int var10 = var9 >> 16 & 255; + final int var11 = var9 >> 8 & 255; + final int var12 = var9 & 255; + final int var13 = -(var5 >> 2); + var5 = -(var5 & 3); + final int var14 = var13 + var13 + var13 + var13 + var5; + + for (int var15 = -var6; var15 < 0; ++var15) { + for (int var16 = var14; var16 < 0; ++var16) { + final int var2 = var1[var3++]; + final int var17 = var2 >>> 24; + if (var17 == 0) { + ++var4; + } else { + final int var19 = var2 >> 16 & 255; + final int var20 = var2 >> 8 & 255; + final int var21 = var2 & 255; + final int var18; + if (var19 == var20 && var20 == var21) { + if (var19 <= 128) { + var18 = (var19 * var10 >> 7 << 16) + (var20 * var11 >> 7 << 8) + (var21 * var12 >> 7); + } else { + var18 = (var10 * (256 - var19) + 255 * (var19 - 128) >> 7 << 16) + (var11 * (256 - var20) + 255 * (var20 - 128) >> 7 << 8) + (var12 * (256 - var21) + 255 * (var21 - 128) >> 7); + } + } else { + var18 = var2; + } + + final int var22 = 256 - var17; + final int var23 = var0[var4]; + var0[var4++] = ((var18 & 16711935) * var17 + (var23 & 16711935) * var22 & -16711936) + ((var18 & '\uff00') * var17 + (var23 & '\uff00') * var22 & 16711680) >>> 8; + } + } + + var4 += var7; + var3 += var8; + } + + } + + @Override + public void drawAdd(int x, int y, final int alpha) { + x += this.x; + y += this.y; + int var4 = Drawing.pixelIndex(x, y); + int var5 = 0; + int var6 = this.height; + int var7 = this.width; + int var8 = Drawing.width - var7; + int var9 = 0; + int var10; + if (y < Drawing.top) { + var10 = Drawing.top - y; + var6 -= var10; + y = Drawing.top; + var5 += var10 * var7; + var4 += var10 * Drawing.width; + } + + if (y + var6 > Drawing.bottom) { + var6 -= y + var6 - Drawing.bottom; + } + + if (x < Drawing.left) { + var10 = Drawing.left - x; + var7 -= var10; + x = Drawing.left; + var5 += var10; + var4 += var10; + var9 += var10; + var8 += var10; + } + + if (x + var7 > Drawing.right) { + var10 = x + var7 - Drawing.right; + var7 -= var10; + var9 += var10; + var8 += var10; + } + + if (var7 > 0 && var6 > 0) { + b057(Drawing.screenBuffer, this.pixels, var5, var4, var7, var6, var8, var9, alpha); + } + } + + @Override + public void drawTinted2(int x, int y, final int color) { + x += this.x; + y += this.y; + int var4 = Drawing.pixelIndex(x, y); + int var5 = 0; + int var6 = this.height; + int var7 = this.width; + int var8 = Drawing.width - var7; + int var9 = 0; + int var10; + if (y < Drawing.top) { + var10 = Drawing.top - y; + var6 -= var10; + y = Drawing.top; + var5 += var10 * var7; + var4 += var10 * Drawing.width; + } + + if (y + var6 > Drawing.bottom) { + var6 -= y + var6 - Drawing.bottom; + } + + if (x < Drawing.left) { + var10 = Drawing.left - x; + var7 -= var10; + x = Drawing.left; + var5 += var10; + var4 += var10; + var9 += var10; + var8 += var10; + } + + if (x + var7 > Drawing.right) { + var10 = x + var7 - Drawing.right; + var7 -= var10; + var9 += var10; + var8 += var10; + } + + if (var7 > 0 && var6 > 0) { + d983(Drawing.screenBuffer, this.pixels, var5, var4, var7, var6, var8, var9, color); + } + } + + @Override + public void b115(int x, int y, int width, int height) { + if (width > 0 && height > 0) { + int var7 = 0; + int var8 = 0; + final int var9 = this.offsetX; + final int var10 = this.offsetY; + final int var11 = (var9 << 16) / width; + final int var12 = (var10 << 16) / height; + int var13; + if (this.x > 0) { + var13 = ((this.x << 16) + var11 - 1) / var11; + x += var13; + var7 += var13 * var11 - (this.x << 16); + } + + if (this.y > 0) { + var13 = ((this.y << 16) + var12 - 1) / var12; + y += var13; + var8 += var13 * var12 - (this.y << 16); + } + + if (this.width < var9) { + width = ((this.width << 16) - var7 + var11 - 1) / var11; + } + + if (this.height < var10) { + height = ((this.height << 16) - var8 + var12 - 1) / var12; + } + + var13 = Drawing.pixelIndex(x, y); + int var14 = Drawing.width - width; + if (y + height > Drawing.bottom) { + height -= y + height - Drawing.bottom; + } + + int var15; + if (y < Drawing.top) { + var15 = Drawing.top - y; + height -= var15; + var13 += var15 * Drawing.width; + var8 += var12 * var15; + } + + if (x + width > Drawing.right) { + var15 = x + width - Drawing.right; + width -= var15; + var14 += var15; + } + + if (x < Drawing.left) { + var15 = Drawing.left - x; + width -= var15; + var13 += var15; + var7 += var11 * var15; + var14 += var15; + } + + c983(Drawing.screenBuffer, this.pixels, var7, var8, var13, var14, width, height, var11, var12, this.width); + } + } + + @Override + public void drawTinted(int x, int y, final int color) { + x += this.x; + y += this.y; + int var4 = Drawing.pixelIndex(x, y); + int var5 = 0; + int var6 = this.height; + int var7 = this.width; + int var8 = Drawing.width - var7; + int var9 = 0; + int var10; + if (y < Drawing.top) { + var10 = Drawing.top - y; + var6 -= var10; + y = Drawing.top; + var5 += var10 * var7; + var4 += var10 * Drawing.width; + } + + if (y + var6 > Drawing.bottom) { + var6 -= y + var6 - Drawing.bottom; + } + + if (x < Drawing.left) { + var10 = Drawing.left - x; + var7 -= var10; + x = Drawing.left; + var5 += var10; + var4 += var10; + var9 += var10; + var8 += var10; + } + + if (x + var7 > Drawing.right) { + var10 = x + var7 - Drawing.right; + var7 -= var10; + var9 += var10; + var8 += var10; + } + + if (var7 > 0 && var6 > 0) { + c663(Drawing.screenBuffer, this.pixels, var5, var4, var7, var6, var8, var9, color); + } + } + + @Override + public void b050(int var1, int var2, int var3, int var4, final int var5) { + if (var3 > 0 && var4 > 0) { + final int var6 = this.width; + final int var7 = this.height; + int var8 = 0; + int var9 = 0; + final int var10 = this.offsetX; + final int var11 = this.offsetY; + final int var12 = (var10 << 16) / var3; + final int var13 = (var11 << 16) / var4; + int var14; + if (this.x > 0) { + var14 = ((this.x << 16) + var12 - 1) / var12; + var1 += var14; + var8 += var14 * var12 - (this.x << 16); + } + + if (this.y > 0) { + var14 = ((this.y << 16) + var13 - 1) / var13; + var2 += var14; + var9 += var14 * var13 - (this.y << 16); + } + + if (var6 < var10) { + var3 = ((var6 << 16) - var8 + var12 - 1) / var12; + } + + if (var7 < var11) { + var4 = ((var7 << 16) - var9 + var13 - 1) / var13; + } + + var14 = Drawing.pixelIndex(var1, var2); + int var15 = Drawing.width - var3; + if (var2 + var4 > Drawing.bottom) { + var4 -= var2 + var4 - Drawing.bottom; + } + + int var16; + if (var2 < Drawing.top) { + var16 = Drawing.top - var2; + var4 -= var16; + var14 += var16 * Drawing.width; + var9 += var13 * var16; + } + + if (var1 + var3 > Drawing.right) { + var16 = var1 + var3 - Drawing.right; + var3 -= var16; + var15 += var16; + } + + if (var1 < Drawing.left) { + var16 = Drawing.left - var1; + var3 -= var16; + var14 += var16; + var8 += var12 * var16; + var15 += var16; + } + + b590(Drawing.screenBuffer, this.pixels, var8, var9, var14, var15, var3, var4, var12, var13, var6, var5); + } + } + + public void i093(int var1, int var2) { + var1 += this.x; + var2 += this.offsetY - this.height - this.y; + int var3 = Drawing.pixelIndex(var1, var2 + this.height - 1); + int var4 = this.width - 1; + int var5 = this.height; + int var6 = this.width; + int var7 = -Drawing.width - var6; + int var8 = var6 + var6; + if (var2 < Drawing.top) { + var5 -= Drawing.top - var2; + var2 = Drawing.top; + } + + int var9; + if (var2 + var5 > Drawing.bottom) { + var9 = var2 + var5 - Drawing.bottom; + var5 -= var9; + var3 -= var9 * Drawing.width; + var4 += var9 * var6; + } + + if (var1 < Drawing.left) { + var9 = Drawing.left - var1; + var6 -= var9; + var1 = Drawing.left; + var4 -= var9; + var3 += var9; + var8 -= var9; + var7 += var9; + } + + if (var1 + var6 > Drawing.right) { + var9 = var1 + var6 - Drawing.right; + var6 -= var9; + var8 -= var9; + var7 += var9; + } + + if (var6 > 0 && var5 > 0) { + d650(Drawing.screenBuffer, this.pixels, var4, var3, var6, var5, var7, var8); + } + } + + @Override + public void g093() { + int var1 = 0; + int var2 = 0; + final int var3 = this.width >> 2; + final int var4 = this.height >> 2; + var1 += this.x / 4; + var2 += this.y / 4; + final int var5 = var1 < Drawing.left ? Drawing.left - var1 << 2 : 0; + final int var6 = var1 + var3 > Drawing.right ? (Drawing.right - var1 << 2) - 4 : this.width - 4; + final int var7 = var2 < Drawing.top ? Drawing.top - var2 << 2 : 0; + final int var8 = var2 + var4 > Drawing.bottom ? (Drawing.bottom - var2 << 2) - 4 : this.height - 4; + final int[] var9 = new int[16]; + + for (int var10 = var7; var10 <= var8; var10 += 4) { + for (int var11 = var5; var11 <= var6; var11 += 4) { + final int var12 = var10 * this.width + var11; + final int var13 = (var2 + (var10 >> 2)) * Drawing.width + var1 + (var11 >> 2); + + int var14; + int var15; + for (var14 = 0; var14 < 4; ++var14) { + for (var15 = 0; var15 < 4; ++var15) { + var9[(var14 << 2) + var15] = this.pixels[var12 + var14 * this.width + var15]; + } + } + + var15 = 0; + int var16 = 0; + int var17 = 0; + int var18 = 0; + + int var19; + for (var19 = 0; var19 < 16; ++var19) { + var14 = var9[var19] >>> 24; + var15 += var14; + var16 += var14 * (var9[var19] >> 16 & 255); + var17 += var14 * (var9[var19] >> 8 & 255); + var18 += var14 * (var9[var19] & 255); + } + + if (var15 != 0) { + var16 = (var16 / var15 << 16) + var18 / var15; + var17 = var17 / var15 << 8; + var19 = var15 >> 4; + final int var20 = 256 - var19; + final int var21 = Drawing.screenBuffer[var13]; + Drawing.screenBuffer[var13] = (var19 * var16 + var20 * (var21 & 16711935) & -16711936) + (var19 * var17 + var20 * (var21 & '\uff00') & 16711680) >>> 8; + } + } + } + + } + + @Override + public void d093(int var1, int var2) { + final int var3 = this.width >> 1; + final int var4 = this.height >> 1; + var1 += this.x / 2; + var2 += this.y / 2; + final int var5 = var1 < Drawing.left ? Drawing.left - var1 << 1 : 0; + final int var6 = var1 + var3 > Drawing.right ? (Drawing.right - var1 << 1) - 2 : this.width - 2; + final int var7 = var2 < Drawing.top ? Drawing.top - var2 << 1 : 0; + final int var8 = var2 + var4 > Drawing.bottom ? (Drawing.bottom - var2 << 1) - 2 : this.height - 2; + + for (int var9 = var7; var9 <= var8; var9 += 2) { + int var10 = var9 * this.width + var5; + int var11 = (var2 + (var9 >> 1)) * Drawing.width + var1 + (var5 >> 1); + + for (int var12 = var5; var12 <= var6; var10 += 2) { + int var15 = 0; + int var16 = 0; + int var17 = 0; + int var18 = 0; + + int var19; + for (var19 = 0; var19 < 4; ++var19) { + final int var22 = this.pixels[var10 + (var19 & 1) + ((var19 & 2) == 0 ? this.width : 0)]; + final int var23 = var22 >>> 24; + var18 += var23; + var15 += var23 * (var22 >> 16 & 255); + var16 += var23 * (var22 >> 8 & 255); + var17 += var23 * (var22 & 255); + } + + if (var18 != 0) { + var15 = (var15 / var18 << 16) + var17 / var18; + var16 = var16 / var18 << 8; + var19 = var18 >> 2; + final int var20 = 256 - var19; + final int var21 = Drawing.screenBuffer[var11]; + Drawing.screenBuffer[var11] = (var19 * var15 + var20 * (var21 & 16711935) & -16711936) + (var19 * var16 + var20 * (var21 & '\uff00') & 16711680) >>> 8; + } + + var12 += 2; + ++var11; + } + } + + } + + @Override + public void a669(int var1, int var2, final int var3, final int var4, final int var5, final int var6) { + if (var6 != 0) { + var1 -= this.x << 4; + var2 -= this.y << 4; + final double var7 = (double) (var5 & '\uffff') * 9.587379924285257E-5D; + final int var9 = (int) Math.floor(Math.sin(var7) * (double) var6 + 0.5D); + final int var10 = (int) Math.floor(Math.cos(var7) * (double) var6 + 0.5D); + final int var11 = -var1 * var10 + -var2 * var9; + final int var12 = -(-var1) * var9 + -var2 * var10; + final int var13 = ((this.width << 4) - var1) * var10 + -var2 * var9; + final int var14 = -((this.width << 4) - var1) * var9 + -var2 * var10; + final int var15 = -var1 * var10 + ((this.height << 4) - var2) * var9; + final int var16 = -(-var1) * var9 + ((this.height << 4) - var2) * var10; + final int var17 = ((this.width << 4) - var1) * var10 + ((this.height << 4) - var2) * var9; + final int var18 = -((this.width << 4) - var1) * var9 + ((this.height << 4) - var2) * var10; + int var19; + int var20; + if (var11 < var13) { + var19 = var11; + var20 = var13; + } else { + var19 = var13; + var20 = var11; + } + + if (var15 < var19) { + var19 = var15; + } + + if (var17 < var19) { + var19 = var17; + } + + if (var15 > var20) { + var20 = var15; + } + + if (var17 > var20) { + var20 = var17; + } + + int var21; + int var22; + if (var12 < var14) { + var21 = var12; + var22 = var14; + } else { + var21 = var14; + var22 = var12; + } + + if (var16 < var21) { + var21 = var16; + } + + if (var18 < var21) { + var21 = var18; + } + + if (var16 > var22) { + var22 = var16; + } + + if (var18 > var22) { + var22 = var18; + } + + var19 >>= 12; + var20 = var20 + 4095 >> 12; + var21 >>= 12; + var22 = var22 + 4095 >> 12; + var19 += var3; + var20 += var3; + var21 += var4; + var22 += var4; + var19 >>= 4; + var20 = var20 + 15 >> 4; + var21 >>= 4; + var22 = var22 + 15 >> 4; + if (var19 < Drawing.left) { + var19 = Drawing.left; + } + + if (var20 > Drawing.right) { + var20 = Drawing.right; + } + + if (var21 < Drawing.top) { + var21 = Drawing.top; + } + + if (var22 > Drawing.bottom) { + var22 = Drawing.bottom; + } + + var20 = var19 - var20; + if (var20 < 0) { + var22 = var21 - var22; + if (var22 < 0) { + int var23 = var21 * Drawing.width + var19; + final double var24 = 1.6777216E7D / (double) var6; + final int var26 = (int) Math.floor(Math.sin(var7) * var24 + 0.5D); + final int var27 = (int) Math.floor(Math.cos(var7) * var24 + 0.5D); + final int var28 = (var19 << 4) + 8 - var3; + final int var29 = (var21 << 4) + 8 - var4; + int var30 = (var1 << 8) - (var29 * var26 >> 4); + int var31 = (var2 << 8) + (var29 * var27 >> 4); + int var32; + int var33; + int var34; + int var35; + int var36; + int var37; + int var38; + int var39; + int var40; + int var41; + if (var27 == 0) { + if (var26 == 0) { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30; + var36 = var31; + var37 = var20; + if (var30 >= 0 && var31 >= 0 && var30 - (this.width << 12) < 0 && var31 - (this.height << 12) < 0) { + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + var39 = Drawing.screenBuffer[var34]; + var40 = var38 >>> 24; + var41 = 256 - var40; + Drawing.screenBuffer[var34++] = ((var38 & 16711935) * var40 + (var39 & 16711935) * var41 & -16711936) + ((var38 & '\uff00') * var40 + (var39 & '\uff00') * var41 & 16711680) >>> 8; + ++var37; + } + } + + ++var33; + } + } else if (var26 < 0) { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30; + var36 = var31 + (var28 * var26 >> 4); + var37 = var20; + if (var30 >= 0 && var30 - (this.width << 12) < 0) { + if ((var32 = var36 - (this.height << 12)) >= 0) { + var32 = (var26 - var32) / var26; + var37 = var20 + var32; + var36 += var26 * var32; + var34 = var23 + var32; + } + + if ((var32 = (var36 - var26) / var26) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + var39 = Drawing.screenBuffer[var34]; + var40 = var38 >>> 24; + var41 = 256 - var40; + Drawing.screenBuffer[var34++] = ((var38 & 16711935) * var40 + (var39 & 16711935) * var41 & -16711936) + ((var38 & '\uff00') * var40 + (var39 & '\uff00') * var41 & 16711680) >>> 8; + var36 += var26; + ++var37; + } + } + + ++var33; + var30 -= var26; + } + } else { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30; + var36 = var31 + (var28 * var26 >> 4); + var37 = var20; + if (var30 >= 0 && var30 - (this.width << 12) < 0) { + if (var36 < 0) { + var32 = (var26 - 1 - var36) / var26; + var37 = var20 + var32; + var36 += var26 * var32; + var34 = var23 + var32; + } + + if ((var32 = (1 + var36 - (this.height << 12) - var26) / var26) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + var39 = Drawing.screenBuffer[var34]; + var40 = var38 >>> 24; + var41 = 256 - var40; + Drawing.screenBuffer[var34++] = ((var38 & 16711935) * var40 + (var39 & 16711935) * var41 & -16711936) + ((var38 & '\uff00') * var40 + (var39 & '\uff00') * var41 & 16711680) >>> 8; + var36 += var26; + ++var37; + } + } + + ++var33; + var30 -= var26; + } + } + } else if (var27 < 0) { + if (var26 == 0) { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30 + (var28 * var27 >> 4); + var36 = var31; + var37 = var20; + if (var31 >= 0 && var31 - (this.height << 12) < 0) { + if ((var32 = var35 - (this.width << 12)) >= 0) { + var32 = (var27 - var32) / var27; + var37 = var20 + var32; + var35 += var27 * var32; + var34 = var23 + var32; + } + + if ((var32 = (var35 - var27) / var27) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + var39 = Drawing.screenBuffer[var34]; + var40 = var38 >>> 24; + var41 = 256 - var40; + Drawing.screenBuffer[var34++] = ((var38 & 16711935) * var40 + (var39 & 16711935) * var41 & -16711936) + ((var38 & '\uff00') * var40 + (var39 & '\uff00') * var41 & 16711680) >>> 8; + var35 += var27; + ++var37; + } + } + + ++var33; + var31 += var27; + } + } else if (var26 < 0) { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30 + (var28 * var27 >> 4); + var36 = var31 + (var28 * var26 >> 4); + var37 = var20; + if ((var32 = var35 - (this.width << 12)) >= 0) { + var32 = (var27 - var32) / var27; + var37 = var20 + var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 = var23 + var32; + } + + if ((var32 = (var35 - var27) / var27) > var37) { + var37 = var32; + } + + if ((var32 = var36 - (this.height << 12)) >= 0) { + var32 = (var26 - var32) / var26; + var37 += var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 += var32; + } + + if ((var32 = (var36 - var26) / var26) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + var39 = Drawing.screenBuffer[var34]; + var40 = var38 >>> 24; + var41 = 256 - var40; + Drawing.screenBuffer[var34++] = ((var38 & 16711935) * var40 + (var39 & 16711935) * var41 & -16711936) + ((var38 & '\uff00') * var40 + (var39 & '\uff00') * var41 & 16711680) >>> 8; + var35 += var27; + var36 += var26; + ++var37; + } + + ++var33; + var30 -= var26; + var31 += var27; + } + } else { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30 + (var28 * var27 >> 4); + var36 = var31 + (var28 * var26 >> 4); + var37 = var20; + if ((var32 = var35 - (this.width << 12)) >= 0) { + var32 = (var27 - var32) / var27; + var37 = var20 + var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 = var23 + var32; + } + + if ((var32 = (var35 - var27) / var27) > var37) { + var37 = var32; + } + + if (var36 < 0) { + var32 = (var26 - 1 - var36) / var26; + var37 += var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 += var32; + } + + if ((var32 = (1 + var36 - (this.height << 12) - var26) / var26) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + var39 = Drawing.screenBuffer[var34]; + var40 = var38 >>> 24; + var41 = 256 - var40; + Drawing.screenBuffer[var34++] = ((var38 & 16711935) * var40 + (var39 & 16711935) * var41 & -16711936) + ((var38 & '\uff00') * var40 + (var39 & '\uff00') * var41 & 16711680) >>> 8; + var35 += var27; + var36 += var26; + ++var37; + } + + ++var33; + var30 -= var26; + var31 += var27; + } + } + } else if (var26 == 0) { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30 + (var28 * var27 >> 4); + var36 = var31; + var37 = var20; + if (var31 >= 0 && var31 - (this.height << 12) < 0) { + if (var35 < 0) { + var32 = (var27 - 1 - var35) / var27; + var37 = var20 + var32; + var35 += var27 * var32; + var34 = var23 + var32; + } + + if ((var32 = (1 + var35 - (this.width << 12) - var27) / var27) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + var39 = Drawing.screenBuffer[var34]; + var40 = var38 >>> 24; + var41 = 256 - var40; + Drawing.screenBuffer[var34++] = ((var38 & 16711935) * var40 + (var39 & 16711935) * var41 & -16711936) + ((var38 & '\uff00') * var40 + (var39 & '\uff00') * var41 & 16711680) >>> 8; + var35 += var27; + ++var37; + } + } + + ++var33; + var31 += var27; + } + } else if (var26 < 0) { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30 + (var28 * var27 >> 4); + var36 = var31 + (var28 * var26 >> 4); + var37 = var20; + if (var35 < 0) { + var32 = (var27 - 1 - var35) / var27; + var37 = var20 + var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 = var23 + var32; + } + + if ((var32 = (1 + var35 - (this.width << 12) - var27) / var27) > var37) { + var37 = var32; + } + + if ((var32 = var36 - (this.height << 12)) >= 0) { + var32 = (var26 - var32) / var26; + var37 += var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 += var32; + } + + if ((var32 = (var36 - var26) / var26) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + var39 = Drawing.screenBuffer[var34]; + var40 = var38 >>> 24; + var41 = 256 - var40; + Drawing.screenBuffer[var34++] = ((var38 & 16711935) * var40 + (var39 & 16711935) * var41 & -16711936) + ((var38 & '\uff00') * var40 + (var39 & '\uff00') * var41 & 16711680) >>> 8; + var35 += var27; + var36 += var26; + ++var37; + } + + ++var33; + var30 -= var26; + var31 += var27; + } + } else { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30 + (var28 * var27 >> 4); + var36 = var31 + (var28 * var26 >> 4); + var37 = var20; + if (var35 < 0) { + var32 = (var27 - 1 - var35) / var27; + var37 = var20 + var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 = var23 + var32; + } + + if ((var32 = (1 + var35 - (this.width << 12) - var27) / var27) > var37) { + var37 = var32; + } + + if (var36 < 0) { + var32 = (var26 - 1 - var36) / var26; + var37 += var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 += var32; + } + + if ((var32 = (1 + var36 - (this.height << 12) - var26) / var26) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + var39 = Drawing.screenBuffer[var34]; + var40 = var38 >>> 24; + var41 = 256 - var40; + Drawing.screenBuffer[var34++] = ((var38 & 16711935) * var40 + (var39 & 16711935) * var41 & -16711936) + ((var38 & '\uff00') * var40 + (var39 & '\uff00') * var41 & 16711680) >>> 8; + var35 += var27; + var36 += var26; + ++var37; + } + + ++var33; + var30 -= var26; + var31 += var27; + } + } + + } + } + } + } + + @Override + public void c093(int x, int y) { + x += this.x; + y += this.y; + int var3 = Drawing.pixelIndex(x, y); + int var4 = 0; + int var5 = this.height; + int var6 = this.width; + int var7 = Drawing.width - var6; + int var8 = 0; + int var9; + if (y < Drawing.top) { + var9 = Drawing.top - y; + var5 -= var9; + y = Drawing.top; + var4 += var9 * var6; + var3 += var9 * Drawing.width; + } + + if (y + var5 > Drawing.bottom) { + var5 -= y + var5 - Drawing.bottom; + } + + if (x < Drawing.left) { + var9 = Drawing.left - x; + var6 -= var9; + x = Drawing.left; + var4 += var9; + var3 += var9; + var8 += var9; + var7 += var9; + } + + if (x + var6 > Drawing.right) { + var9 = x + var6 - Drawing.right; + var6 -= var9; + var8 += var9; + var7 += var9; + } + + if (var6 > 0 && var5 > 0) { + this.compositeOver(this.pixels, var8, var4, Drawing.screenBuffer, var7, var3, var6, var5); + } + } + + @Override + public ArgbSprite copy() { + final ArgbSprite sprite = new ArgbSprite(this.width, this.height); + sprite.x = this.x; + sprite.y = this.y; + sprite.offsetX = this.offsetX; + sprite.offsetY = this.offsetY; + System.arraycopy(this.pixels, 0, sprite.pixels, 0, this.pixels.length); + return sprite; + } + + public void h093(int var1, int var2) { + var1 += this.offsetX - this.width - this.x; + var2 += this.y; + int var3 = Drawing.pixelIndex(var1, var2); + int var4 = this.width - 1; + int var5 = this.height; + int var6 = this.width; + int var7 = Drawing.width - var6; + int var8 = var6 + var6; + int var9; + if (var2 < Drawing.top) { + var9 = Drawing.top - var2; + var5 -= var9; + var2 = Drawing.top; + var4 += var9 * var6; + var3 += var9 * Drawing.width; + } + + if (var2 + var5 > Drawing.bottom) { + var5 -= var2 + var5 - Drawing.bottom; + } + + if (var1 < Drawing.left) { + var9 = Drawing.left - var1; + var6 -= var9; + var1 = Drawing.left; + var4 -= var9; + var3 += var9; + var8 -= var9; + var7 += var9; + } + + if (var1 + var6 > Drawing.right) { + var9 = var1 + var6 - Drawing.right; + var6 -= var9; + var8 -= var9; + var7 += var9; + } + + if (var6 > 0 && var5 > 0) { + d650(Drawing.screenBuffer, this.pixels, var4, var3, var6, var5, var7, var8); + } + } + + @Override + public void draw(int x, int y, final int alpha) { + x += this.x; + y += this.y; + int var4 = Drawing.pixelIndex(x, y); + int var5 = 0; + int var6 = this.height; + int var7 = this.width; + int var8 = Drawing.width - var7; + int var9 = 0; + int var10; + if (y < Drawing.top) { + var10 = Drawing.top - y; + var6 -= var10; + y = Drawing.top; + var5 += var10 * var7; + var4 += var10 * Drawing.width; + } + + if (y + var6 > Drawing.bottom) { + var6 -= y + var6 - Drawing.bottom; + } + + if (x < Drawing.left) { + var10 = Drawing.left - x; + var7 -= var10; + x = Drawing.left; + var5 += var10; + var4 += var10; + var9 += var10; + var8 += var10; + } + + if (x + var7 > Drawing.right) { + var10 = x + var7 - Drawing.right; + var7 -= var10; + var9 += var10; + var8 += var10; + } + + if (var7 > 0 && var6 > 0) { + d663(Drawing.screenBuffer, this.pixels, var5, var4, var7, var6, var8, var9, alpha); + } + } +} diff --git a/src/main/java/funorb/graphics/Drawing.java b/src/main/java/funorb/graphics/Drawing.java new file mode 100644 index 0000000..1499f7c --- /dev/null +++ b/src/main/java/funorb/graphics/Drawing.java @@ -0,0 +1,2132 @@ +package funorb.graphics; + +import funorb.util.ArrayUtil; +import funorb.util.MathUtil; + +import java.util.Arrays; + +public final class Drawing { + public static final int[] SHADES_OF_GRAY = ArrayUtil.build(256, i -> i * 0x010101); + public static final int BLACK = 0x000000; + public static final int WHITE = 0xffffff; + public static final int MAX_ALPHA = 256; + public static final int RED = 0xff0000; + public static final int GREEN = 0x00ff00; + public static final int YELLOW = 0xffff00; + public static int[] screenBuffer; + public static int width; + public static int height; + public static int left = 0; + public static int top = 0; + public static int right = 0; + public static int bottom = 0; + + private static final int SAVE_STACK_DEPTH = 4; + private static int saveIndex = 0; + private static final int[][] savedScreenBuffer = new int[SAVE_STACK_DEPTH][]; + private static final int[] savedWidth = new int[SAVE_STACK_DEPTH]; + private static final int[] savedHeight = new int[SAVE_STACK_DEPTH]; + private static final int[] savedLeft = new int[SAVE_STACK_DEPTH]; + private static final int[] savedTop = new int[SAVE_STACK_DEPTH]; + private static final int[] savedRight = new int[SAVE_STACK_DEPTH]; + private static final int[] savedBottom = new int[SAVE_STACK_DEPTH]; + + private static final int[] _fev = new int[7]; + static { + for (int var0 = 0; var0 < 3; ++var0) { + _fev[var0] = 0x404040 * (1 + var0); + _fev[6 - var0] = 0x404040 + var0 * 0x404040; + } + _fev[3] = WHITE; + } + + private static int[] _e; + private static int[] _g; + private static int[] _j; + + public static void initialize(final int[] screenBuffer, final int width, final int height) { + Drawing.screenBuffer = screenBuffer; + Drawing.width = width; + Drawing.height = height; + setBounds(0, 0, width, height); + } + + public static void setBounds(final int left, final int top, final int right, final int bottom) { + Drawing.left = Math.max(left, 0); + Drawing.top = Math.max(top, 0); + Drawing.right = Math.min(right, width); + Drawing.bottom = Math.min(bottom, height); + } + + public static void expandBoundsToInclude(final int left, final int top, final int right, final int bottom) { + if (Drawing.left < left) { + Drawing.left = left; + } + if (Drawing.top < top) { + Drawing.top = top; + } + if (Drawing.right > right) { + Drawing.right = right; + } + if (Drawing.bottom > bottom) { + Drawing.bottom = bottom; + } + } + + public static void saveContext() { + savedScreenBuffer[saveIndex] = screenBuffer; + savedLeft[saveIndex] = left; + savedRight[saveIndex] = right; + savedTop[saveIndex] = top; + savedBottom[saveIndex] = bottom; + savedWidth[saveIndex] = width; + savedHeight[saveIndex] = height; + ++saveIndex; + } + + public static void restoreContext() { + --saveIndex; + initialize(savedScreenBuffer[saveIndex], savedWidth[saveIndex], savedHeight[saveIndex]); + left = savedLeft[saveIndex]; + right = savedRight[saveIndex]; + top = savedTop[saveIndex]; + bottom = savedBottom[saveIndex]; + } + + public static void withLocalContext(final Runnable action) { + final int[] screenBuffer = Drawing.screenBuffer; + final int width = Drawing.width; + final int height = Drawing.height; + final int left = Drawing.left; + final int top = Drawing.top; + final int right = Drawing.right; + final int bottom = Drawing.bottom; + try { + action.run(); + } finally { + initialize(screenBuffer, width, height); + setBounds(left, top, right, bottom); + } + } + + public static void e115(int var2, int var3) { + int var0 = 0; + int var1 = 0; + if (var0 < left) { + var2 -= left - var0; + var0 = left; + } + + if (var0 + var2 > right) { + var2 = right - var0; + } + + if (var1 < top) { + var3 -= top - var1; + var1 = top; + } + + if (var1 + var3 > bottom) { + var3 = bottom - var1; + } + + int var4 = pixelIndex(var0, var1); + if (var2 > 0 && var3 > 0) { + for (int var5 = 0; var5 < var3; ++var5) { + for (int var6 = 0; var6 < var2; ++var6) { + final int var7 = screenBuffer[var4]; + final int var8 = (var7 >> 15) & 510; + final int var9 = (var7 >> 8) & 0xff; + final int var10 = var7 & 0xff; + final int var11 = (((var10 + var8) / 3) + var9) >> 1; + screenBuffer[var4++] = (var11 << 16) + (var11 << 8) + var11; + } + + var4 += width - var2; + } + } + } + + public static int pixelIndex(final int x, final int y) { + return x + y * width; + } + + public static void b669(final int var0, final int var1, final int var4, final int var5) { + a600(screenBuffer, var0, var4, width - var4, var5); + a621(screenBuffer, var1, var5, width - var4, var4); + } + + @SuppressWarnings("SameParameterValue") + public static void verticalLineBlended(final int x, int y, int height, final int color) { + if (x >= left && x < right) { + if (y < top) { + height -= top - y; + y = top; + } + + if (y + height > bottom) { + height = bottom - y; + } + + int n = pixelIndex(x, y); + for (int i = 0; i < height; ++i) { + final int color1 = screenBuffer[n]; + final int sum = color + color1; + final int rb = (color & 0xff00ff) + (color1 & 0xff00ff); + final int overflow = (rb & 0x01000100) + ((sum - rb) & 0x010000); + screenBuffer[n] = (sum - overflow) | (overflow - (overflow >>> 8)); + n += width; + } + } + } + + public static void f669(final int var0, final int var1, final int var2, final int var3, int var4, final int var5) { + if (var4 == 0) { + strokeRectangle(var0, var1, var2, var3, var5); + } else { + if (var4 < 0) { + var4 = -var4; + } + + final int var6 = var0 + var4; + final int var7 = var1 + var4; + final int var8 = var0 + var2 - var4 - 1; + final int var9 = var1 + var3 - var4 - 1; + if (right > left && bottom > top) { + if (var0 + var2 > left && var0 < right && var1 + var3 >= top && var1 < bottom) { + int var10 = pixelIndex(var6, (var7 - var4)); + int var11 = pixelIndex(var8, (var7 - var4)); + int var12 = pixelIndex(var6, var7); + int var13 = pixelIndex(var8, var7); + int var14 = pixelIndex(var6, var9); + int var15 = pixelIndex(var8, var9); + int var16 = pixelIndex(var6, (var9 + var4)); + int var17 = pixelIndex(var8, (var9 + var4)); + int var18 = var4; + int var19 = 0; + final int var20 = var4 * var4; + int var21 = var20 - var4; + if (var0 >= left && var0 + var2 < right && var1 >= top && var1 + var3 < bottom) { + int var22; + for (var22 = var12; var22 <= var14; var22 += width) { + screenBuffer[var22 - var18] = var5; + } + + for (var22 = var13; var22 <= var15; var22 += width) { + screenBuffer[var22 + var18] = var5; + } + + for (var22 = var10; var22 <= var11; ++var22) { + screenBuffer[var22] = var5; + } + + for (var22 = var16; var22 <= var17; ++var22) { + screenBuffer[var22] = var5; + } + + while (true) { + var21 += var19++ + var19; + var12 -= width; + var13 -= width; + var14 += width; + var15 += width; + if (var21 > var20) { + --var18; + var21 -= var18 + var18; + var10 += width; + var11 += width; + var16 -= width; + var17 -= width; + } + + if (var18 < var19) { + break; + } + + screenBuffer[var10 - var19] = var5; + screenBuffer[var11 + var19] = var5; + screenBuffer[var12 - var18] = var5; + screenBuffer[var13 + var18] = var5; + screenBuffer[var14 - var18] = var5; + screenBuffer[var15 + var18] = var5; + screenBuffer[var16 - var19] = var5; + screenBuffer[var17 + var19] = var5; + } + } else { + verticalLine(var0, var1 + var4, var3 - var4 - var4, var5); + verticalLine(var0 + var2 - 1, var1 + var4, var3 - var4 - var4, var5); + horizontalLine(var0 + var4, var1, var2 - var4 - var4, var5); + horizontalLine(var0 + var4, var1 + var3 - 1, var2 - var4 - var4, var5); + + while (true) { + var21 += var19++ + var19; + var12 -= width; + var13 -= width; + var14 += width; + var15 += width; + if (var21 > var20) { + --var18; + var21 -= var18 + var18; + var10 += width; + var11 += width; + var16 -= width; + var17 -= width; + } + + if (var18 < var19) { + break; + } + + if (var7 - var18 >= top && var7 - var18 < bottom) { + if (var6 - var19 >= left && var6 - var19 < right) { + screenBuffer[var10 - var19] = var5; + } + + if (var8 + var19 >= left && var8 + var19 < right) { + screenBuffer[var11 + var19] = var5; + } + } + + if (var7 - var19 >= top && var7 - var19 < bottom) { + if (var6 - var18 >= left && var6 - var18 < right) { + screenBuffer[var12 - var18] = var5; + } + + if (var8 + var18 >= left && var8 + var18 < right) { + screenBuffer[var13 + var18] = var5; + } + } + + if (var9 + var19 >= top && var9 + var19 < bottom) { + if (var6 - var18 >= left && var6 - var18 < right) { + screenBuffer[var14 - var18] = var5; + } + + if (var8 + var18 >= left && var8 + var18 < right) { + screenBuffer[var15 + var18] = var5; + } + } + + if (var9 + var18 >= top && var9 + var18 < bottom) { + if (var6 - var19 >= left && var6 - var19 < right) { + screenBuffer[var16 - var19] = var5; + } + + if (var8 + var19 >= left && var8 + var19 < right) { + screenBuffer[var17 + var19] = var5; + } + } + } + } + + } + } + } + } + + public static void fillRoundedRect(final int x, final int y, final int width, final int height, final int radius, final int color) { + if (radius == 0) { + fillRect(x, y, width, height, color); + return; + } + + final int var4a = Math.abs(radius); + + final int var6 = x + var4a; + int var7 = y + var4a; + final int yStart = Math.max(y, top); + final int yEnd = Math.min(y + height, bottom); + + final int var10 = width - var4a - var4a - 1; + final int var12 = var4a * var4a; + int var13 = 0; + int var14 = var7 - yStart; + int var15 = var14 * var14; + int var16 = var15 - var14; + if (var7 > yEnd) { + var7 = yEnd; + } + + int y1 = yStart; + while (y1 < var7) { + while (var16 <= var12 || var15 <= var12) { + var15 += var13 + var13; + var16 += var13++ + var13; + } + + final int var17 = Math.max(var6 - var13 + 1, left); + final int var18 = Math.min(var6 + var10 + var13, right); + + int var19 = pixelIndex(var17, y1); + for (int i = var17; i < var18; ++i) { + screenBuffer[var19++] = color; + } + + ++y1; + var15 -= var14-- + var14; + var16 -= var14 + var14; + } + + final int var17 = Math.max(x, left); + final int var18 = Math.min(x + width, right); + + int var19 = pixelIndex(var17, y1); + final int var20 = Drawing.width + var17 - var18; + final int var21 = Math.min(y + height - var4a - 1, bottom); + + while (y1 < var21) { + for (int var22 = var17; var22 < var18; ++var22) { + screenBuffer[var19++] = color; + } + + ++y1; + var19 += var20; + } + + int var41 = var4a; + int var121 = var12; + int i1 = var121 - var4a; + + int i = 0; + for (; y1 < yEnd; y1++) { + while (var121 > var12 && i1 > var12) { + var121 -= var41-- + var41; + i1 -= var41 + var41; + } + + final int var17a = Math.max(var6 - var41, left); + final int var18a = Math.min(var6 + var10 + var41, right - 1); + int var19a = pixelIndex(var17a, y1); + for (int var20a = var17a; var20a <= var18a; ++var20a) { + screenBuffer[var19a++] = color; + } + + var121 += i + i; + i1 += i + i; + i++; + } + } + + public static void drawCircleGradientAdd(final int x, final int y, final int radius, final int alpha, final int[] colors) { + final int x1 = Math.max((x - radius) >> 4, left); + final int x2 = Math.min((x + radius + 15) >> 4, right); + final int y1 = Math.max((y - radius) >> 4, top); + final int y2 = Math.min((y + radius + 15) >> 4, bottom); + + final int var10 = MathUtil.square((x1 << 4) - x); + final int var11 = MathUtil.square((x1 + 1 << 4) - x); + final int var12 = MathUtil.square((x1 + 2 << 4) - x); + final int var13 = var11 - var10; + final int var15 = (var12 - var11) - var13; + final int var16 = MathUtil.square((y1 << 4) - y); + final int var17 = MathUtil.square(((y1 + 1) << 4) - y); + final int var18 = MathUtil.square(((y1 + 2) << 4) - y); + final int var21 = (var18 - var17) - (var17 - var16); + final int var23 = width + x1 - x2; + + int n = pixelIndex(x1, y1); + int var141 = var16 + var10; + int var151 = var17 - var16; + final int radius2 = MathUtil.square(radius); + int i = y1 - y2; + while (i < 0) { + int var31 = var141; + int var41 = var13; + + for (int j = x1 - x2; j < 0; ++j) { + if (var31 < radius2) { + final int color1 = colors[(radius2 - var31) * alpha / radius2]; + final int color2 = screenBuffer[n]; + final int sum = color1 + color2; + final int rb = (color1 & 0xff00ff) + (color2 & 0xff00ff); + final int var25 = (rb & 0x01000100) + ((sum - rb) & 0x010000); + screenBuffer[n] = (sum - var25) | (var25 - (var25 >>> 8)); + } + + ++n; + var31 += var41; + var41 += var15; + } + + n += var23; + var141 += var151; + var151 += var21; + ++i; + } + } + + public static void fillCircle(final int x, int y, int radius, final int color, final int alpha) { + if (alpha == 0) return; + if (alpha == 256) { + fillCircle(x, y, radius, color); + return; + } + + if (radius < 0) { + radius = -radius; + } + + final int alpha2 = 256 - alpha; + final int var6 = (color >> 16 & 255) * alpha; + final int var7 = (color >> 8 & 255) * alpha; + final int var8 = (color & 255) * alpha; + int var12 = y - radius; + if (var12 < top) { + var12 = top; + } + + int var13 = y + radius + 1; + if (var13 > bottom) { + var13 = bottom; + } + + int var14 = var12; + final int var15 = radius * radius; + int var16 = 0; + int var17 = y - var12; + int var18 = var17 * var17; + int var19 = var18 - var17; + if (y > var13) { + y = var13; + } + + int var9; + int var10; + int var11; + int var20; + int var21; + int var22; + int var23; + int var24; + while (var14 < y) { + while (var19 <= var15 || var18 <= var15) { + var18 += var16 + var16; + var19 += var16++ + var16; + } + + var20 = x - var16 + 1; + if (var20 < left) { + var20 = left; + } + + var21 = x + var16; + if (var21 > right) { + var21 = right; + } + + var22 = pixelIndex(var20, var14); + + for (var23 = var20; var23 < var21; ++var23) { + var9 = (screenBuffer[var22] >> 16 & 255) * alpha2; + var10 = (screenBuffer[var22] >> 8 & 255) * alpha2; + var11 = (screenBuffer[var22] & 255) * alpha2; + var24 = (var6 + var9 >> 8 << 16) + (var7 + var10 >> 8 << 8) + (var8 + var11 >> 8); + screenBuffer[var22++] = var24; + } + + ++var14; + var18 -= var17-- + var17; + var19 -= var17 + var17; + } + + int i = radius; + var17 = -var17; + int i1 = var17 * var17 + var15; + int i2 = i1 - radius; + + for (i1 -= var17; var14 < var13; i2 += var17++ + var17) { + while (i1 > var15 && i2 > var15) { + i1 -= i-- + i; + i2 -= i + i; + } + + var20 = x - i; + if (var20 < left) { + var20 = left; + } + + var21 = x + i; + if (var21 > right - 1) { + var21 = right - 1; + } + + var22 = pixelIndex(var20, var14); + + for (var23 = var20; var23 <= var21; ++var23) { + var9 = (screenBuffer[var22] >> 16 & 255) * alpha2; + var10 = (screenBuffer[var22] >> 8 & 255) * alpha2; + var11 = (screenBuffer[var22] & 255) * alpha2; + var24 = (var6 + var9 >> 8 << 16) + (var7 + var10 >> 8 << 8) + (var8 + var11 >> 8); + screenBuffer[var22++] = var24; + } + + ++var14; + i1 += var17 + var17; + } + + } + + public static void fillRect(int x, int y, int width, int height, final int color) { + if (x < left) { + width -= left - x; + x = left; + } + + if (y < top) { + height -= top - y; + y = top; + } + + if (x + width > right) { + width = right - x; + } + + if (y + height > bottom) { + height = bottom - y; + } + + final int stride = Drawing.width - width; + int n = pixelIndex(x, y); + for (int i = 0; i < height; ++i) { + for (int j = 0; j < width; ++j) { + screenBuffer[n++] = color; + } + n += stride; + } + } + + public static void h115(int x, int y, int width, int height) { + if (x < left) { + width -= left - x; + x = left; + } + if (y < top) { + height -= top - y; + y = top; + } + if (x + width > right) { + width = right - x; + } + if (y + height > bottom) { + height = bottom - y; + } + + final int stride = Drawing.width - width; + int n = pixelIndex(x, y); + for (int i = 0; i < height; ++i) { + for (int j = 0; j < width; ++j) { + screenBuffer[n] = (screenBuffer[n] & 0xfefefe) >> 1; + ++n; + } + n += stride; + } + } + + private static void e669(int var0, int var1, int var2, int var3, final int var5) { + int var6 = 0; + final int var7 = 65536 / var3; + if (var0 < left) { + var2 -= left - var0; + var0 = left; + } + + if (var1 < top) { + var6 += (top - var1) * var7; + var3 -= top - var1; + var1 = top; + } + + if (var0 + var2 > right) { + var2 = right - var0; + } + + if (var1 + var3 > bottom) { + var3 = bottom - var1; + } + + final int var8 = width - var2; + int var9 = pixelIndex(var0, var1); + + for (int var10 = -var3; var10 < 0; ++var10) { + final int var12 = var6 >> 8; + final int var13 = ((var5 & 16711935) * var12 & -16711936) + ((var5 & '\uff00') * var12 & 16711680) >>> 8; + + for (int var14 = -var2; var14 < 0; ++var14) { + final int var15 = screenBuffer[var9]; + final int var16 = var13 + var15; + final int var17 = (var13 & 16711935) + (var15 & 16711935); + final int i = (var17 & 16777472) + (var16 - var17 & 65536); + screenBuffer[var9++] = var16 - i | i - (i >>> 8); + } + + var9 += var8; + var6 += var7; + } + + } + + public static void h669(int var0, int var1, int var2, int var3, final int var4, final int var5) { + var2 -= var0; + var3 -= var1; + if (var3 == 0) { + if (var2 >= 0) { + horizontalLine(var0, var1, var2 + 1, var4, var5); + } else { + horizontalLine(var0 + var2, var1, -var2 + 1, var4, var5); + } + + } else if (var2 == 0) { + if (var3 >= 0) { + verticalLine(var0, var1, var3 + 1, var4, var5); + } else { + verticalLine(var0, var1 + var3, -var3 + 1, var4, var5); + } + + } else { + if (var2 + var3 < 0) { + var0 += var2; + var2 = -var2; + var1 += var3; + var3 = -var3; + } + + final int var6 = 256 - var5; + final int var7 = (var4 >> 16 & 255) * var5; + final int var8 = (var4 >> 8 & 255) * var5; + final int var9 = (var4 & 255) * var5; + final int var10; + int var11; + int var12; + int var13; + int var14; + int var15; + int var16; + if (var2 > var3) { + var1 <<= 16; + var1 += 32768; + var3 <<= 16; + var10 = (int) Math.floor((double) var3 / (double) var2 + 0.5D); + var2 += var0; + if (var0 < left) { + var1 += var10 * (left - var0); + var0 = left; + } + + if (var2 >= right) { + var2 = right - 1; + } + + while (var0 <= var2) { + var11 = var1 >> 16; + if (var11 >= top && var11 < bottom) { + var12 = pixelIndex(var0, var11); + var13 = (screenBuffer[var12] >> 16 & 255) * var6; + var14 = (screenBuffer[var12] >> 8 & 255) * var6; + var15 = (screenBuffer[var12] & 255) * var6; + var16 = (var7 + var13 >> 8 << 16) + (var8 + var14 >> 8 << 8) + (var9 + var15 >> 8); + screenBuffer[var12] = var16; + } + + var1 += var10; + ++var0; + } + } else { + var0 <<= 16; + var0 += 32768; + var2 <<= 16; + var10 = (int) Math.floor((double) var2 / (double) var3 + 0.5D); + var3 += var1; + if (var1 < top) { + var0 += var10 * (top - var1); + var1 = top; + } + + if (var3 >= bottom) { + var3 = bottom - 1; + } + + while (var1 <= var3) { + var11 = var0 >> 16; + if (var11 >= left && var11 < right) { + var12 = pixelIndex(var11, var1); + var13 = (screenBuffer[var12] >> 16 & 255) * var6; + var14 = (screenBuffer[var12] >> 8 & 255) * var6; + var15 = (screenBuffer[var12] & 255) * var6; + var16 = (var7 + var13 >> 8 << 16) + (var8 + var14 >> 8 << 8) + (var9 + var15 >> 8); + screenBuffer[var12] = var16; + } + + var0 += var10; + ++var1; + } + } + + } + } + + private static void a621(final int[] var0, final int var3, final int var5, final int var6, final int var8) { + int var2 = 0; + if (_e == null || _e.length < var8) { + _e = new int[var8]; + _j = new int[var8]; + _g = new int[var8]; + } + + final int[] var9 = _e; + final int[] var10 = _j; + final int[] var11 = _g; + Arrays.fill(var9, 0, var8, 0); + Arrays.fill(var10, 0, var8, 0); + Arrays.fill(var11, 0, var8, 0); + final int var12 = 16384 / (2 * var3 + 1); + int var13 = -var3; + if (var13 < 0) { + var13 = 0; + } + + int var14 = var13 * width; + int var15 = var3; + int var16 = 0; + if (var15 >= height) { + var16 = var15 - height + 1; + var15 = height - 1; + } + + int var17; + int var18; + int var1; + for (var17 = var15 - var13 + 1; var13 <= var15; ++var13) { + for (var18 = 0; var18 < var8; ++var18) { + var1 = var0[var14++]; + var9[var18] += var1 >> 16 & 255; + var10[var18] += var1 >> 8 & 255; + var11[var18] += var1 & 255; + } + + var14 += var6; + } + + var14 += var16 * width; + + for (var18 = 0; var18 < var8; ++var18) { + var0[var2++] = (var9[var18] / var17 << 16) + (var10[var18] / var17 << 8) + var11[var18] / var17; + } + + var2 += var6; + int i = 1 - var5; + var18 = 1 + var3 - var5; + if (var18 > 0) { + var18 = 0; + } + + int var19 = (-var3) * width; + if (i < var18) { + var19 += (var18 - i) * width; + } + + int var20; + int var21; + int var22; + int var23; + while (i < var18) { + if (i + var5 + var3 >= bottom) { + var14 += width; + } else { + for (var20 = 0; var20 < var8; ++var20) { + var1 = var0[var14++]; + var9[var20] += var1 >> 16 & 255; + var10[var20] += var1 >> 8 & 255; + var11[var20] += var1 & 255; + } + + var14 += var6; + ++var17; + } + + for (var20 = 0; var20 < var8; ++var20) { + var21 = var9[var20] / var17; + var22 = var10[var20] / var17; + var23 = var11[var20] / var17; + var0[var2++] = (var21 << 16) + (var22 << 8) + var23; + } + + var2 += var6; + ++i; + } + + var18 = height - var5 - var3; + if (var18 > 0) { + var18 = 0; + } + + while (i < var18) { + for (var20 = 0; var20 < var8; ++var20) { + var1 = var0[var19++]; + var21 = var9[var20] - (var1 >> 16 & 255); + var9[var20] = Math.max(var21, 0); + var21 = var10[var20] - (var1 >> 8 & 255); + var10[var20] = Math.max(var21, 0); + var21 = var11[var20] - (var1 & 255); + var11[var20] = Math.max(var21, 0); + } + + var19 += var6; + + for (var20 = 0; var20 < var8; ++var20) { + var1 = var0[var14++]; + var9[var20] += var1 >> 16 & 255; + var10[var20] += var1 >> 8 & 255; + var11[var20] += var1 & 255; + } + + var14 += var6; + + for (var20 = 0; var20 < var8; ++var20) { + var21 = var9[var20] * var12 >> 14; + var22 = var10[var20] * var12 >> 14; + var23 = var11[var20] * var12 >> 14; + if (var21 > 255) { + var21 = 255; + } + + if (var22 > 255) { + var22 = 255; + } + + if (var23 > 255) { + var23 = 255; + } + + var0[var2++] = (var21 << 16) + (var22 << 8) + var23; + } + + var2 += var6; + ++i; + } + + while (i < 0) { + for (var20 = 0; var20 < var8; ++var20) { + var1 = var0[var19++]; + var9[var20] -= var1 >> 16 & 255; + var10[var20] -= var1 >> 8 & 255; + var11[var20] -= var1 & 255; + } + + var19 += var6; + --var17; + + for (var20 = 0; var20 < var8; ++var20) { + var21 = var9[var20] / var17; + var22 = var10[var20] / var17; + var23 = var11[var20] / var17; + if (var21 < 0) { + var21 = 0; + } else if (var21 > 255) { + var21 = 255; + } + + if (var22 < 0) { + var22 = 0; + } else if (var22 > 255) { + var22 = 255; + } + + if (var23 < 0) { + var23 = 0; + } else if (var23 > 255) { + var23 = 255; + } + + var0[var2++] = (var21 << 16) + (var22 << 8) + var23; + } + + var2 += var6; + ++i; + } + + } + + public static void strokeCircle(final int x, final int y, int radius, final int color) { + if (radius == 0) { + setPixel(x, y, color); + } else { + if (radius < 0) { + radius = -radius; + } + + if (right > left && bottom > top) { + if (x + radius >= left && x - radius < right && y + radius >= top && y - radius < bottom) { + int var4 = pixelIndex(x, y); + int var5 = var4; + int var6 = var4 - radius * width; + int var7 = pixelIndex(var4, radius); + int var8 = radius; + int var9 = 0; + radius *= radius; + int var10 = radius - var8; + if (x - var8 >= left && x + var8 < right && y - var8 >= top && y + var8 < bottom) { + screenBuffer[var4 - var8] = color; + screenBuffer[var4 + var8] = color; + screenBuffer[var6] = color; + screenBuffer[var7] = color; + + while (true) { + var10 += var9++ + var9; + var4 -= width; + var5 += width; + if (var10 > radius) { + --var8; + var10 -= var8 + var8; + var6 += width; + var7 -= width; + } + + if (var8 < var9) { + break; + } + + screenBuffer[var6 - var9] = color; + screenBuffer[var6 + var9] = color; + screenBuffer[var4 - var8] = color; + screenBuffer[var4 + var8] = color; + screenBuffer[var5 - var8] = color; + screenBuffer[var5 + var8] = color; + screenBuffer[var7 - var9] = color; + screenBuffer[var7 + var9] = color; + } + } else { + if (x - var8 >= left && y >= top && y < bottom) { + screenBuffer[var4 - var8] = color; + } + + if (x + var8 < right && y >= top && y < bottom) { + screenBuffer[var4 + var8] = color; + } + + if (y - var8 >= top && x >= left && x < right) { + screenBuffer[var6] = color; + } + + if (y + var8 < bottom && x >= left && x < right) { + screenBuffer[var7] = color; + } + + while (true) { + var10 += var9++ + var9; + var4 -= width; + var5 += width; + if (var10 > radius) { + --var8; + var10 -= var8 + var8; + var6 += width; + var7 -= width; + } + + if (var8 < var9) { + break; + } + + if (y - var8 >= top && y - var8 < bottom) { + if (x - var9 >= left && x - var9 < right) { + screenBuffer[var6 - var9] = color; + } + + if (x + var9 >= left && x + var9 < right) { + screenBuffer[var6 + var9] = color; + } + } + + if (y - var9 >= top && y - var9 < bottom) { + if (x - var8 >= left && x - var8 < right) { + screenBuffer[var4 - var8] = color; + } + + if (x + var8 >= left && x + var8 < right) { + screenBuffer[var4 + var8] = color; + } + } + + if (y + var9 >= top && y + var9 < bottom) { + if (x - var8 >= left && x - var8 < right) { + screenBuffer[var5 - var8] = color; + } + + if (x + var8 >= left && x + var8 < right) { + screenBuffer[var5 + var8] = color; + } + } + + if (y + var8 >= top && y + var8 < bottom) { + if (x - var9 >= left && x - var9 < right) { + screenBuffer[var7 - var9] = color; + } + + if (x + var9 >= left && x + var9 < right) { + screenBuffer[var7 + var9] = color; + } + } + } + } + } + } + } + } + + public static void verticalLine(final int x, int y, int height, final int color, final int alpha) { + if (x >= left && x < right) { + if (y < top) { + height -= top - y; + y = top; + } + + if (y + height > bottom) { + height = bottom - y; + } + + final int var5 = 256 - alpha; + final int var6 = (color >> 16 & 255) * alpha; + final int var7 = (color >> 8 & 255) * alpha; + final int var8 = (color & 255) * alpha; + int var12 = pixelIndex(x, y); + + for (int var13 = 0; var13 < height; ++var13) { + final int var9 = (screenBuffer[var12] >> 16 & 255) * var5; + final int var10 = (screenBuffer[var12] >> 8 & 255) * var5; + final int var11 = (screenBuffer[var12] & 255) * var5; + final int var14 = (var6 + var9 >> 8 << 16) + (var7 + var10 >> 8 << 8) + (var8 + var11 >> 8); + screenBuffer[var12] = var14; + var12 += width; + } + + } + } + + public static void strokeRectangle(final int x, final int y, final int width, final int height, final int color) { + horizontalLine(x, y, width, color); + horizontalLine(x, y + height - 1, width, color); + verticalLine(x, y, height, color); + verticalLine(x + width - 1, y, height, color); + } + + public static void verticalLine(final int x, int y, int height, final int color) { + if (x >= left && x < right) { + if (y < top) { + height -= top - y; + y = top; + } + + if (y + height > bottom) { + height = bottom - y; + } + + int var4 = pixelIndex(x, y); + + for (int var5 = 0; var5 < height; var4 += width) { + screenBuffer[var4] = color; + ++var5; + } + + } + } + + public static void b370(final int var0, int var1, final int var2, int var3, int var4, final int var6) { + if (var4 == 0) { + e669(var0, var1, var2, var3, var6); + } else { + if (var4 < 0) { + var4 = -var4; + } + + int var7 = 0; + final int var8 = 65536 / var3; + final int var9 = var0 + var4; + int var10 = var1 + var4; + int var11 = var1; + if (var1 < top) { + var7 += (top - var1) * var8; + var3 -= top - var1; + var1 = var11 = top; + } + + int var12 = var1 + var3; + if (var12 > bottom) { + var12 = bottom; + } + + final int var13 = var2 - var4 - var4 - 1; + int var14 = var11; + final int var15 = var4 * var4; + int var16 = 0; + int var17 = var10 - var11; + int var18 = var17 * var17; + int var19 = var18 - var17; + if (var10 > var12) { + var10 = var12; + } + + int var20; + int var21; + int var22; + final int var23; + int var24; + int var25; + int var26; + while (var14 < var10) { + while (var19 <= var15 || var18 <= var15) { + var18 += var16 + var16; + var19 += var16++ + var16; + } + + var20 = var9 - var16 + 1; + if (var20 < left) { + var20 = left; + } + + var21 = var9 + var13 + var16; + if (var21 > right) { + var21 = right; + } + + var22 = pixelIndex(var20, var14); + var24 = var7 >> 8; + var25 = ((var6 & 16711935) * var24 & -16711936) + ((var6 & '\uff00') * var24 & 16711680) >>> 8; + + for (var26 = var20; var26 < var21; ++var26) { + screenBuffer[var22++] = var25; + } + + ++var14; + var18 -= var17-- + var17; + var19 -= var17 + var17; + var7 += var8; + } + + var20 = Math.max(var0, left); + + var21 = var0 + var2; + if (var21 > right) { + var21 = right; + } + + var22 = pixelIndex(var20, var14); + var23 = width + var20 - var21; + var24 = var1 + var3 - var4 - 1; + if (var24 > bottom) { + var24 = bottom; + } + + while (var14 < var24) { + var26 = var7 >> 8; + final int var27 = ((var6 & 16711935) * var26 & -16711936) + ((var6 & '\uff00') * var26 & 16711680) >>> 8; + + for (int var28 = var20; var28 < var21; ++var28) { + screenBuffer[var22++] = var27; + } + + ++var14; + var22 += var23; + var7 += var8; + } + + int i = 0; + int var41 = var4; + int var151 = var15; + int i1 = var151 - var4; + + for (var151 -= i; var14 < var12; var7 += var8) { + while (var151 > var15 && i1 > var15) { + var151 -= var41-- + var41; + i1 -= var41 + var41; + } + + var20 = var9 - var41; + if (var20 < left) { + var20 = left; + } + + var21 = var9 + var13 + var41; + if (var21 > right - 1) { + var21 = right - 1; + } + + var22 = pixelIndex(var20, var14); + var24 = var7 >> 8; + var25 = ((var6 & 16711935) * var24 & -16711936) + ((var6 & '\uff00') * var24 & 16711680) >>> 8; + + for (var26 = var20; var26 <= var21; ++var26) { + screenBuffer[var22++] = var25; + } + + ++var14; + var151 += i + i; + i1 += i++ + i; + } + + } + } + + public static void a797() { + left = 0; + top = 0; + right = width; + bottom = height; + } + + public static void horizontalLine(int x, final int y, int width, final int color, final int alpha) { + if (y >= top && y < bottom) { + if (x < left) { + width -= left - x; + x = left; + } + if (x + width > right) { + width = right - x; + } + + final int alpha2 = 256 - alpha; + final int r1 = ((color >> 16) & 0xff) * alpha; + final int g1 = ((color >> 8) & 0xff) * alpha; + final int b1 = (color & 0xff) * alpha; + + int n = pixelIndex(x, y); + for (int i = 0; i < width; ++i) { + final int r2 = ((screenBuffer[n] >> 16) & 255) * alpha2; + final int g2 = ((screenBuffer[n] >> 8) & 255) * alpha2; + final int b2 = (screenBuffer[n] & 255) * alpha2; + screenBuffer[n++] = (((r1 + r2) >> 8) << 16) + + (((g1 + g2) >> 8) << 8) + + ((b1 + b2) >> 8); + } + } + } + + public static void fillRect(int x, int y, int width, int height, int color, final int alpha) { + if (x < left) { + width -= left - x; + x = left; + } + if (y < top) { + height -= top - y; + y = top; + } + if (x + width > right) { + width = right - x; + } + if (y + height > bottom) { + height = bottom - y; + } + + color = ((((color & 0xff00ff) * alpha) >> 8) & 0xff00ff) + ((((color & 0x00ff00) * alpha) >> 8) & 0x00ff00); + final int occlusion = 256 - alpha; + final int stride = Drawing.width - width; + + int n = pixelIndex(x, y); + for (int i = 0; i < height; ++i) { + for (int j = -width; j < 0; ++j) { + final int px = screenBuffer[n]; + final int px2 = ((px & 0xff00ff) * occlusion >> 8 & 0xff00ff) + ((px & 0x00ff00) * occlusion >> 8 & 0x00ff00); + screenBuffer[n++] = color + px2; + } + n += stride; + } + } + + public static void restoreBoundsFrom(final int[] bounds) { + left = bounds[0]; + top = bounds[1]; + right = bounds[2]; + bottom = bounds[3]; + } + + public static void saveBoundsTo(final int[] bounds) { + bounds[0] = left; + bounds[1] = top; + bounds[2] = right; + bounds[3] = bottom; + } + + public static void withSavedBounds(final Runnable action) { + final int left = Drawing.left; + final int top = Drawing.top; + final int right = Drawing.right; + final int bottom = Drawing.bottom; + try { + action.run(); + } finally { + setBounds(left, top, right, bottom); + } + } + + @SuppressWarnings("SameParameterValue") + public static void withBounds(final int left, final int top, final int right, final int bottom, final Runnable action) { + withSavedBounds(() -> { + setBounds(left, top, right, bottom); + action.run(); + }); + } + + public static void fillRoundedRect(final int x, final int y, final int width, final int height, int radius, int color, final int alpha) { + if (alpha == 256) { + fillRoundedRect(x, y, width, height, radius, color); + } else if (radius == 0) { + fillRect(x, y, width, height, color, alpha); + } else { + final int var7 = 256 - alpha; + color = ((color & 16711935) * alpha >> 8 & 16711935) + ((color & '\uff00') * alpha >> 8 & '\uff00'); + if (radius < 0) { + radius = -radius; + } + + final int var8 = x + radius; + int var9 = y + radius; + final int var10 = Math.max(y, top); + + int var11 = y + height; + if (var11 > bottom) { + var11 = bottom; + } + + final int var12 = width - radius - radius - 1; + int var13 = var10; + final int var14 = radius * radius; + int var15 = 0; + int var16 = var9 - var10; + int var17 = var16 * var16; + int var18 = var17 - var16; + if (var9 > var11) { + var9 = var11; + } + + int var19; + int var20; + int var21; + int var22; + int var23; + while (var13 < var9) { + while (var18 <= var14 || var17 <= var14) { + var17 += var15 + var15; + var18 += var15++ + var15; + } + + var19 = var8 - var15 + 1; + if (var19 < left) { + var19 = left; + } + + var20 = var8 + var12 + var15; + if (var20 > right) { + var20 = right; + } + + var21 = pixelIndex(var19, var13); + + for (var22 = var19; var22 < var20; ++var22) { + var23 = screenBuffer[var21]; + var23 = ((var23 & 16711935) * var7 >> 8 & 16711935) + ((var23 & '\uff00') * var7 >> 8 & '\uff00'); + screenBuffer[var21++] = color + var23; + } + + ++var13; + var17 -= var16-- + var16; + var18 -= var16 + var16; + } + + var19 = Math.max(x, left); + + var20 = x + width; + if (var20 > right) { + var20 = right; + } + + var21 = pixelIndex(var19, var13); + var22 = Drawing.width + var19 - var20; + var23 = y + height - radius - 1; + if (var23 > bottom) { + var23 = bottom; + } + + while (var13 < var23) { + for (int var24 = var19; var24 < var20; ++var24) { + int var25 = screenBuffer[var21]; + var25 = ((var25 & 16711935) * var7 >> 8 & 16711935) + ((var25 & '\uff00') * var7 >> 8 & '\uff00'); + screenBuffer[var21++] = color + var25; + } + + ++var13; + var21 += var22; + } + + int i = 0; + int var41 = radius; + int var141 = var14; + int i1 = var141 - radius; + + for (var141 -= i; var13 < var11; i1 += i++ + i) { + while (var141 > var14 && i1 > var14) { + var141 -= var41-- + var41; + i1 -= var41 + var41; + } + + var19 = var8 - var41; + if (var19 < left) { + var19 = left; + } + + var20 = var8 + var12 + var41; + if (var20 > right - 1) { + var20 = right - 1; + } + + var21 = pixelIndex(var19, var13); + + for (var22 = var19; var22 <= var20; ++var22) { + var23 = screenBuffer[var21]; + var23 = ((var23 & 16711935) * var7 >> 8 & 16711935) + ((var23 & '\uff00') * var7 >> 8 & '\uff00'); + screenBuffer[var21++] = color + var23; + } + + ++var13; + var141 += i + i; + } + + } + } + + private static boolean a398(final int var5, final int var6, int var7, int var8, final int[] var9, final int var12, final int var13, final int var14) { + int var3 = var14; + + int var4; + for (var4 = var13; var8 < 0; ++var8) { + final int var1 = (var6 - var3) * 12 / var6; + if (var1 >= _fev.length) { + return true; + } + + int var0 = _fev[var1]; + final int i = var9[var7]; + final int var2 = var0 + i; + var0 = (var0 & 16711935) + (i & 16711935); + final int i1 = (var0 & 16777472) + (var2 - var0 & 65536); + var9[var7] = var2 - i1 | i1 - (i1 >>> 8); + var7 += var12; + var3 += var4; + var4 += var5; + } + + return false; + } + + public static void d669(final int var0, final int var1, final int var2, final int var3, final int var4, final int var5) { + horizontalLine(var0, var1, var2, var4, var5); + horizontalLine(var0, var1 + var3 - 1, var2, var4, var5); + if (var3 >= 3) { + verticalLine(var0, var1 + 1, var3 - 2, var4, var5); + verticalLine(var0 + var2 - 1, var1 + 1, var3 - 2, var4, var5); + } + + } + + public static void setPixel(final int x, final int y, final int color) { + if (x >= left && x < right && y >= top && y < bottom) { + screenBuffer[pixelIndex(x, y)] = color; + } + } + + public static void line(int x1, int y1, final int x2, final int y2, final int color, final int alpha) { + int width = x2 - x1; + int height = y2 - y1; + if (height == 0) { + if (width >= 0) { + horizontalLine(x1, y1, width, color, alpha); + } else { + horizontalLine(x1 + width + 1, y1, -width, color, alpha); + } + } else if (width == 0) { + if (height >= 0) { + verticalLine(x1, y1, height, color, alpha); + } else { + verticalLine(x1, y1 + height + 1, -height, color, alpha); + } + } else { + boolean var6 = false; + if (width + height < 0) { + x1 += width; + width = -width; + y1 += height; + height = -height; + var6 = true; + } + + final int var7 = 256 - alpha; + final int var8 = (color >> 16 & 255) * alpha; + final int var9 = (color >> 8 & 255) * alpha; + final int var10 = (color & 255) * alpha; + final int var11; + int var12; + int var13; + int var14; + int var15; + int var16; + int var17; + if (width > height) { + y1 <<= 16; + y1 += 32768; + height <<= 16; + var11 = (int) Math.floor((double) height / (double) width + 0.5D); + width += x1; + if (var6) { + y1 += var11; + ++x1; + } + + if (x1 < left) { + y1 += var11 * (left - x1); + x1 = left; + } + + if (width >= right) { + width = right - 1; + } + + if (!var6) { + --width; + } + + while (x1 <= width) { + var12 = y1 >> 16; + if (var12 >= top && var12 < bottom) { + var13 = pixelIndex(x1, var12); + var14 = (screenBuffer[var13] >> 16 & 255) * var7; + var15 = (screenBuffer[var13] >> 8 & 255) * var7; + var16 = (screenBuffer[var13] & 255) * var7; + var17 = (var8 + var14 >> 8 << 16) + (var9 + var15 >> 8 << 8) + (var10 + var16 >> 8); + screenBuffer[var13] = var17; + } + + y1 += var11; + ++x1; + } + } else { + x1 <<= 16; + x1 += 32768; + width <<= 16; + var11 = (int) Math.floor((double) width / (double) height + 0.5D); + height += y1; + if (var6) { + x1 += var11; + ++y1; + } + + if (y1 < top) { + x1 += var11 * (top - y1); + y1 = top; + } + + if (height >= bottom) { + height = bottom - 1; + } + + if (!var6) { + --height; + } + + while (y1 <= height) { + var12 = x1 >> 16; + if (var12 >= left && var12 < right) { + var13 = pixelIndex(var12, y1); + var14 = (screenBuffer[var13] >> 16 & 255) * var7; + var15 = (screenBuffer[var13] >> 8 & 255) * var7; + var16 = (screenBuffer[var13] & 255) * var7; + var17 = (var8 + var14 >> 8 << 16) + (var9 + var15 >> 8 << 8) + (var10 + var16 >> 8); + screenBuffer[var13] = var17; + } + + x1 += var11; + ++y1; + } + } + + } + } + + public static void fillCircle(final int x, int y, final int radius, final int color) { + if (radius == 0) { + setPixel(x, y, color); + return; + } + + final int radiusPos = Math.abs(radius); + final int radiusSq = MathUtil.square(radiusPos); + + final int y1 = Math.max(y - radiusPos, top); + final int y2 = Math.min(y + radiusPos + 1, bottom); + + int var9 = y - y1; + int var10 = var9 * var9; + int var11 = var10 - var9; + if (y > y2) { + y = y2; + } + + int yi = y1; + for (int ri = 0; yi < y; ++yi) { + while (var11 <= radiusSq || var10 <= radiusSq) { + var10 += ri + ri; + var11 += ri + ri; + ri++; + } + + final int x1 = Math.max(x - ri + 1, left); + final int x2 = Math.min(x + ri, right); + int n = pixelIndex(x1, yi); + for (int i = x1; i < x2; ++i) { + screenBuffer[n++] = color; + } + + var10 -= var9 + var9; + var9--; + var11 -= var9 + var9; + } + + int i0 = radiusPos; + int i1 = yi - y; + int i2 = MathUtil.square(i1) + radiusSq; + int i3 = i2 - radiusPos; + i2 -= i1; + + for (; yi < y2; ++yi) { + while (i2 > radiusSq && i3 > radiusSq) { + i2 -= i0 + i0; + i0--; + i3 -= i0 + i0; + } + + final int x1 = Math.max(x - i0, left); + final int x2 = Math.min(x + i0, right - 1); + int n = pixelIndex(x1, yi); + for (int i = x1; i <= x2; ++i) { + screenBuffer[n++] = color; + } + + i2 += i1 + i1; + i3 += i1 + i1; + i1++; + } + } + + private static void a600(final int[] var0, final int var3, final int var5, final int var6, final int var7) { + int var2 = 0; + final int var8 = 16384 / (2 * var3 + 1); + int var9 = 1 + var3 - var5; + if (var9 > 0) { + var9 = 0; + } + + int var10 = width - var5 - var3; + if (var10 > 0) { + var10 = 0; + } + + int var11 = 0; + int var12 = var3 + 1; + if (width < var12) { + var11 = var12 - width; + var12 = width; + } + + for (int var13 = -var7; var13 < 0; ++var13) { + int var14 = 0; + int var15 = 0; + int var16 = 0; + int var17 = var2 - var3; + int var18 = var17 - (var3 << 1) - 1; + int var19 = -var3; + if (var19 < 0) { + var17 -= var19; + var18 -= var19; + var19 = 0; + } + + int var20; + int var1; + for (var20 = var12 - var19; var19 < var12; ++var19) { + var1 = var0[var17]; + var14 += var1 >> 16 & 255; + var15 += var1 >> 8 & 255; + var16 += var1 & 255; + ++var17; + ++var18; + } + + var18 += var11; + var0[var2++] = (var14 / var20 << 16) + (var15 / var20 << 8) + var16 / var20; + + int var21; + int var22; + int var23; + for (var19 = 1 - var5; var19 < var9; ++var19) { + ++var18; + if (var5 + var19 + var3 < right) { + var1 = var0[var17]; + ++var17; + var14 += var1 >> 16 & 255; + var15 += var1 >> 8 & 255; + var16 += var1 & 255; + ++var20; + } + + var21 = var14 / var20; + var22 = var15 / var20; + var23 = var16 / var20; + var0[var2++] = (var21 << 16) + (var22 << 8) + var23; + } + + while (var19 < var10) { + var1 = var0[var18++]; + var14 -= var1 >> 16 & 255; + if (var14 < 0) { + var14 = 0; + } + + var15 -= var1 >> 8 & 255; + if (var15 < 0) { + var15 = 0; + } + + var16 -= var1 & 255; + if (var16 < 0) { + var16 = 0; + } + + var1 = var0[var17]; + ++var17; + var14 += var1 >> 16 & 255; + var15 += var1 >> 8 & 255; + var16 += var1 & 255; + var21 = var14 * var8 >> 14; + var22 = var15 * var8 >> 14; + var23 = var16 * var8 >> 14; + if (var21 > 255) { + var21 = 255; + } + + if (var22 > 255) { + var22 = 255; + } + + if (var23 > 255) { + var23 = 255; + } + + var0[var2++] = (var21 << 16) + (var22 << 8) + var23; + ++var19; + } + + while (var19 < 0) { + var1 = var0[var18++]; + var14 -= var1 >> 16 & 255; + var15 -= var1 >> 8 & 255; + var16 -= var1 & 255; + --var20; + var21 = var14 / var20; + var22 = var15 / var20; + var23 = var16 / var20; + if (var21 < 0) { + var21 = 0; + } else if (var21 > 255) { + var21 = 255; + } + + if (var22 < 0) { + var22 = 0; + } else if (var22 > 255) { + var22 = 255; + } + + if (var23 < 0) { + var23 = 0; + } else if (var23 > 255) { + var23 = 255; + } + + var0[var2++] = (var21 << 16) + (var22 << 8) + var23; + ++var19; + } + + var2 += var6; + } + + } + + public static void addPixel(final int x, final int y, final int color, final int alpha) { + if (x >= left && y >= top && x < right && y < bottom) { + final int i = pixelIndex(x, y); + screenBuffer[i] = saturatingAdd(color, screenBuffer[i], alpha); + } + } + + public static void fillRectangleVerticalGradient(int x, int y, int width, int height, final int color1, final int color2) { + if (x < left) { + width -= left - x; + x = left; + } + + int var6 = 0; + final int var7 = 0x10000 / height; + if (y < top) { + var6 += (top - y) * var7; + height -= top - y; + y = top; + } + + if (x + width > right) { + width = right - x; + } + + if (y + height > bottom) { + height = bottom - y; + } + + final int var8 = Drawing.width - width; + int pos = pixelIndex(x, y); + + for (int i = 0; i < height; ++i) { + final int var11 = (0x10000 - var6) >> 8; + final int var12 = var6 >> 8; + final int var13 = ((color1 & 0xff00ff) * var11 + (color2 & 0xff00ff) * var12 & 0xff00ff00) + ((color1 & 0x00ff00) * var11 + (color2 & 0x00ff00) * var12 & 0xff0000) >>> 8; + + for (int j = 0; j < width; ++j) { + screenBuffer[pos++] = var13; + } + + pos += var8; + var6 += var7; + } + } + + public static void clear() { + Arrays.fill(screenBuffer, 0, width * height, 0); + } + + public static void line(int x1, int y1, final int x2, final int y2, final int color) { + int dx = x2 - x1; + int dy = y2 - y1; + if (dy == 0) { + if (dx >= 0) { + horizontalLine(x1, y1, dx + 1, color); + } else { + horizontalLine(x1 + dx, y1, -dx + 1, color); + } + + } else if (dx == 0) { + if (dy >= 0) { + verticalLine(x1, y1, dy + 1, color); + } else { + verticalLine(x1, y1 + dy, -dy + 1, color); + } + + } else { + if (dx + dy < 0) { + x1 += dx; + dx = -dx; + y1 += dy; + dy = -dy; + } + + final int var5; + int var6; + if (dx > dy) { + y1 <<= 16; + y1 += 32768; + dy <<= 16; + var5 = (int) Math.floor((double) dy / (double) dx + 0.5D); + dx += x1; + if (x1 < left) { + y1 += var5 * (left - x1); + x1 = left; + } + + if (dx >= right) { + dx = right - 1; + } + + while (x1 <= dx) { + var6 = y1 >> 16; + if (var6 >= top && var6 < bottom) { + screenBuffer[pixelIndex(x1, var6)] = color; + } + + y1 += var5; + ++x1; + } + } else { + x1 <<= 16; + x1 += 32768; + dx <<= 16; + var5 = (int) Math.floor((double) dx / (double) dy + 0.5D); + dy += y1; + if (y1 < top) { + x1 += var5 * (top - y1); + y1 = top; + } + + if (dy >= bottom) { + dy = bottom - 1; + } + + while (y1 <= dy) { + var6 = x1 >> 16; + if (var6 >= left && var6 < right) { + screenBuffer[pixelIndex(var6, y1)] = color; + } + + x1 += var5; + ++y1; + } + } + + } + } + + public static void a907(final int var0, final int var1, final int var2) { + final int var5 = var2 * var2; + int var6 = var1 - var2 >> 4; + int var7 = var1 + var2 + 15 >> 4; + if (var6 < top) { + var6 = top; + } + + if (var7 > bottom) { + var7 = bottom; + } + + int var8 = (var6 << 4) - var1; + var8 *= var8; + int var9 = (var6 + 1 << 4) - var1; + var9 *= var9; + int var10 = (var6 + 2 << 4) - var1; + var10 *= var10; + int var11 = var9 - var8; + final int var12 = var10 - var9; + final int var13 = var12 - var11; + int var14 = var6 * width; + final int var15 = width; + + for (int var16 = var6 - var7; var16 < 0; ++var16) { + int var17 = var0 - var2 >> 4; + int var18 = var0 + var2 + 15 >> 4; + if (var17 < left) { + var17 = left; + } + + if (var18 > right) { + var18 = right; + } + + int var19 = var0 + 15 >> 4; + int var20 = var19; + + int var21; + int var22; + while (var17 < var19) { + var21 = var17 + var19 >> 1; + var22 = (var21 << 4) - var0; + var22 *= var22; + if (var8 + var22 < var5) { + var19 = var21; + } else { + var17 = var21 + 1; + } + } + + while (var18 > var20) { + var21 = var20 + var18 >> 1; + var22 = (var21 << 4) - var0; + var22 *= var22; + if (var8 + var22 < var5) { + var20 = var21 + 1; + } else { + var18 = var21; + } + } + + var21 = (var17 << 4) - var0; + var21 *= var21; + var22 = (var17 + 1 << 4) - var0; + var22 *= var22; + int var23 = (var17 + 2 << 4) - var0; + var23 *= var23; + final int var24 = var22 - var21; + final int var25 = var23 - var22; + final int var26 = var25 - var24; + int var27 = (var18 - 1 << 4) - var0; + var27 *= var27; + int var28 = (var18 - 2 << 4) - var0; + var28 *= var28; + final int var29 = var28 - var27; + final boolean var30 = a398(var26, var5, var14 + var17, var17 - var18, screenBuffer, 1, var24, var8 + var21); + if (var30) { + a398(var26, var5, var14 + var18 - 1, var17 - var18, screenBuffer, -1, var29, var8 + var27); + } + + var14 += var15; + var8 += var11; + var11 += var13; + } + } + + public static void horizontalLine(int x, final int y, int width, final int color) { + if (y >= top && y < bottom) { + if (x < left) { + width -= left - x; + x = left; + } + + if (x + width > right) { + width = right - x; + } + + final int var4 = pixelIndex(x, y); + for (int i = 0; i < width; ++i) { + screenBuffer[var4 + i] = color; + } + } + } + + public static int alphaOver(final int color1, final int color2, final int alpha) { + final int rb1 = color1 & 0xff00ff; + final int g1 = color1 & 0x00ff00; + return alphaOver(rb1, g1, color2, alpha); + } + + public static int alphaOver(final int rb1, final int g1, final int color2, final int alpha) { + final int alpha2 = 256 - alpha; + final int rb2 = color2 & 0xff00ff; + final int g2 = color2 & 0x00ff00; + final int rb3 = ((rb1 * alpha + rb2 * alpha2) >>> 8) & 0xeaff00ff; + final int g3 = (( g1 * alpha + g2 * alpha2) >>> 8) & 0x9600ff00; + return rb3 | g3; + } + + public static int saturatingAdd(final int color1, final int color2) { + final int sum = color1 + color2; + final int rb_sum = (color1 & 0xff00ff) + (color2 & 0xff00ff); + final int g_sum = sum - rb_sum; + final int overflow = (rb_sum & 0x01_00_01_00) + (g_sum & 0x01_00_00); + return (sum - overflow) | (overflow - (overflow >>> 8)); + } + + public static int saturatingAdd(final int srcColor, final int destColor, final int srcAlpha) { + final int rb1 = (srcColor & 0xff00ff) * srcAlpha; + final int g1 = (srcColor * srcAlpha) - rb1; + final int color1 = ((rb1 & 0xff00ff00) + (g1 & 0xff0000)) >>> 8; + final int sum = color1 + destColor; + final int rb_sum = (color1 & 0xff00ff) + (destColor & 0xff00ff); + final int g_sum = sum - rb_sum; + final int overflow = (rb_sum & 0x01_00_01_00) + (g_sum & 0x01_00_00); + return (sum - overflow) | (overflow - (overflow >>> 8)); + } + + public static int gray(final int value) { + return (value << 16) | (value << 8) | value; + } +} diff --git a/src/main/java/funorb/graphics/Font.java b/src/main/java/funorb/graphics/Font.java new file mode 100644 index 0000000..0621f83 --- /dev/null +++ b/src/main/java/funorb/graphics/Font.java @@ -0,0 +1,846 @@ +package funorb.graphics; + +import funorb.Strings; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +public abstract class Font { + /** + * Set by {@link #breakLines(String, int)}. + */ + private static final String[] BROKEN_LINES = new String[100]; + + private static int globalShadowColor = -1; + private static int spaceWidth = 0; + private static int spaceWidthError = 0; + private static int underlineColor = -1; + private static int strikethroughColor = -1; + private static int globalAlpha = 256; + private static int localAlpha = 256; + private static int localShadowColor = -1; + private static int localColor = 0; + private static int globalColor = 0; + + public int baseline = 0; + public final int ascent; + public final int descent; + public final int capHeight; + private int[] advanceWidths; + private byte[] kerns; + + private final int[] glyphOriginsX; + private final int[] glyphOriginsY; + private final int[] inkWidths; + private final int[] inkHeights; + + private Symbol[] symbols; + private int[] symbolAscents; + + protected Font(final byte[] metricsData, final int[] glyphOriginsX, final int[] glyphOriginsY, final int[] inkWidths, final int[] inkHeights) { + this.glyphOriginsX = glyphOriginsX; + this.glyphOriginsY = glyphOriginsY; + this.inkWidths = inkWidths; + this.inkHeights = inkHeights; + this.parseMetrics(metricsData); + + int inkBoundAbove = Integer.MAX_VALUE; + int inkBoundBelow = Integer.MIN_VALUE; + for (int i = 0; i < 256; ++i) { + if (inkBoundAbove > this.glyphOriginsY[i] && this.inkHeights[i] != 0) { + inkBoundAbove = this.glyphOriginsY[i]; + } + + if (inkBoundBelow < this.glyphOriginsY[i] + this.inkHeights[i]) { + inkBoundBelow = this.glyphOriginsY[i] + this.inkHeights[i]; + } + } + + this.ascent = this.baseline - inkBoundAbove; + this.descent = inkBoundBelow - this.baseline; + this.capHeight = this.baseline - this.glyphOriginsY[88]; + } + + public final void setSymbols(final Symbol[] symbols, final int[] ascents) { + if (ascents == null || ascents.length == symbols.length) { + this.symbols = symbols; + this.symbolAscents = ascents; + } else { + throw new IllegalArgumentException(); + } + } + + // + public static String escapeTags(final String text) { + final int var1 = text.length(); + int var2 = 0; + + for (int var3 = 0; var3 < var1; ++var3) { + final char var4 = text.charAt(var3); + if (var4 == '<' || var4 == '>') { + var2 += 3; + } + } + + final StringBuilder var6 = new StringBuilder(var1 + var2); + + for (int var7 = 0; var7 < var1; ++var7) { + final char var5 = text.charAt(var7); + if (var5 == '<') { + var6.append(""); + } else if (var5 == '>') { + var6.append(""); + } else { + var6.append(var5); + } + } + + return var6.toString(); + } + + private static void parseAttrTag(final String str) { + try { + if (str.startsWith("col=")) { + localColor = Strings.parseHexInteger(str.substring(4)); + } else if (str.equals("/col")) { + localColor = globalColor; + } else if (str.startsWith("trans=")) { + localAlpha = Strings.parseDecimalInteger(str.substring(6)); + } else if (str.equals("/trans")) { + localAlpha = globalAlpha; + } else if (str.startsWith("str=")) { + strikethroughColor = Strings.parseHexInteger(str.substring(4)); + } else if (str.equals("str")) { + strikethroughColor = 0x800000; + } else if (str.equals("/str")) { + strikethroughColor = -1; + } else if (str.startsWith("u=")) { + underlineColor = Strings.parseHexInteger(str.substring(2)); + } else if (str.equals("u")) { + underlineColor = 0; + } else if (str.equals("/u")) { + underlineColor = -1; + } else if (str.startsWith("shad=")) { + localShadowColor = Strings.parseHexInteger(str.substring(5)); + } else if (str.equals("shad")) { + localShadowColor = 0; + } else if (str.equals("/shad")) { + localShadowColor = globalShadowColor; + } else if (str.equals("br")) { + setFormattingParams(globalColor, globalShadowColor, globalAlpha); + } + } catch (final Exception var3) { + } + } + // + + // + public final int getAdvanceWidth(final char c) { + return this.advanceWidths[Strings.encode1252Char(c) & 255]; + } + + private int getKerning(final char glyph1, final char glyph2) { + if (this.kerns == null || glyph1 == 0) { + return 0; + } else { + return this.kerns[(glyph1 << 8) + glyph2]; + } + } + + @Contract(pure = true) + public final int measureLineWidth(final String str) { + if (str == null) { + return 0; + } + + int openBracketPos = -1; + char prevChar = 0; + int width = 0; + for (int i = 0; i < str.length(); ++i) { + char c = str.charAt(i); + if (c == '<') { + openBracketPos = i; + } else { + if (c == '>' && openBracketPos != -1) { + final String command = str.substring(openBracketPos + 1, i).toLowerCase(); + openBracketPos = -1; + switch (command) { + case "lt": + c = '<'; + break; + case "gt": + break; + case "nbsp": + c = 160; + break; + case "shy": + c = 173; + break; + case "times": + c = 215; + break; + case "euro": + c = 8364; + break; + case "copy": + c = 169; + break; + case "reg": + c = 174; + break; + default: + if (command.startsWith("img=")) { + try { + final int symbolId = Strings.parseDecimalInteger(command.substring(4)); + width += this.symbols[symbolId].advanceX; + prevChar = 0; + } catch (final Exception var10) {} + } + } + } + + if (openBracketPos == -1) { + c = (char) (Strings.encode1252Char(c) & 255); + width += this.advanceWidths[c]; + if (this.kerns != null && prevChar != 0) { + width += this.kerns[(prevChar << 8) + c]; + } + + prevChar = c; + } + } + } + + return width; + } + + public final int breakLines(final String text, final int lineWidth) { + return this.breakLines(text, new int[]{lineWidth}, BROKEN_LINES); + } + + /** + * @return the number of lines + */ + public final int breakLines(final String text, final int[] lineWidths, final String[] lines) { + if (text == null) { + return 0; + } + + final StringBuilder sb = new StringBuilder(); + int width = 0; + int lastBreakIndex = 0; + int breakIndex = -1; + int breakWidth = 0; + byte breakSkip = 0; + char lastGlyphIndex = 0; + int lineIndex = 0; + + int tagStartIndex = -1; + for (int i = 0; i < text.length(); ++i) { + char glyphIndex = text.charAt(i); + if (glyphIndex == '<') { + tagStartIndex = i; + } else { + if (glyphIndex == '>' && tagStartIndex != -1) { + final String tag = text.substring(tagStartIndex + 1, i).toLowerCase(); + tagStartIndex = -1; + sb.append('<'); + sb.append(tag); + sb.append('>'); + if (tag.equals("br")) { + lines[lineIndex] = sb.substring(lastBreakIndex, sb.length()); + ++lineIndex; + lastBreakIndex = sb.length(); + width = 0; + breakIndex = -1; + lastGlyphIndex = 0; + } else if (tag.equals("lt")) { + width += this.getAdvanceWidth('<'); + if (this.kerns != null && lastGlyphIndex != 0) { + width += this.kerns[(lastGlyphIndex << 8) + 60]; + } + + lastGlyphIndex = '<'; + } else if (tag.equals("gt")) { + width += this.getAdvanceWidth('>'); + if (this.kerns != null && lastGlyphIndex != 0) { + width += this.kerns[(lastGlyphIndex << 8) + 62]; + } + + lastGlyphIndex = '>'; + } else if (tag.equals("nbsp")) { + width += this.getAdvanceWidth(' '); + if (this.kerns != null && lastGlyphIndex != 0) { + width += this.kerns[(lastGlyphIndex << 8) + 160]; + } + + lastGlyphIndex = 160; + } else if (tag.equals("shy")) { + width += this.getAdvanceWidth('\u00ad'); + if (this.kerns != null && lastGlyphIndex != 0) { + width += this.kerns[(lastGlyphIndex << 8) + 173]; + } + + lastGlyphIndex = 173; + } else if (tag.equals("times")) { + width += this.getAdvanceWidth('×'); + if (this.kerns != null && lastGlyphIndex != 0) { + width += this.kerns[(lastGlyphIndex << 8) + 215]; + } + + lastGlyphIndex = 215; + } else if (tag.equals("euro")) { + width += this.getAdvanceWidth('€'); + if (this.kerns != null && lastGlyphIndex != 0) { + width += this.kerns[(lastGlyphIndex << 8) + 128]; + } + + lastGlyphIndex = 8364; + } else if (tag.equals("copy")) { + width += this.getAdvanceWidth('©'); + if (this.kerns != null && lastGlyphIndex != 0) { + width += this.kerns[(lastGlyphIndex << 8) + 169]; + } + + lastGlyphIndex = 169; + } else if (tag.equals("reg")) { + width += this.getAdvanceWidth('®'); + if (this.kerns != null && lastGlyphIndex != 0) { + width += this.kerns[(lastGlyphIndex << 8) + 174]; + } + + lastGlyphIndex = 174; + } else if (tag.startsWith("img=")) { + try { + final int var16 = Strings.parseDecimalInteger(tag.substring(4)); + width += this.symbols[var16].advanceX; + lastGlyphIndex = 0; + } catch (final Exception var17) { + } + } + glyphIndex = 0; + } + + if (tagStartIndex == -1) { + if (glyphIndex != 0) { + sb.append(glyphIndex); + glyphIndex = (char) (Strings.encode1252Char(glyphIndex) & 255); + width += this.advanceWidths[glyphIndex]; + if (this.kerns != null && lastGlyphIndex != 0) { + width += this.kerns[(lastGlyphIndex << 8) + glyphIndex]; + } + + lastGlyphIndex = glyphIndex; + } + + if (glyphIndex == ' ') { + breakIndex = sb.length(); + breakWidth = width; + breakSkip = 1; + } + + if (lineWidths != null) { + final int widthIndex = lineIndex < lineWidths.length ? lineIndex : lineWidths.length - 1; + if (width > lineWidths[widthIndex] && breakIndex >= 0) { + lines[lineIndex] = sb.substring(lastBreakIndex, breakIndex - breakSkip); + ++lineIndex; + lastBreakIndex = breakIndex; + breakIndex = -1; + width -= breakWidth; + lastGlyphIndex = 0; + } + } + + if (glyphIndex == '-') { + breakIndex = sb.length(); + breakWidth = width; + breakSkip = 0; + } + } + } + } + + if (sb.length() > lastBreakIndex) { + lines[lineIndex] = sb.substring(lastBreakIndex, sb.length()); + ++lineIndex; + } + + return lineIndex; + } + + public final int measureParagraphWidth(final String text, final int targetLineWidth) { + final int lineCount = this.breakLines(text, new int[]{targetLineWidth}, BROKEN_LINES); + + int width = 0; + for (int i = 0; i < lineCount; ++i) { + final int lineWidth = this.measureLineWidth(BROKEN_LINES[i]); + if (lineWidth > width) { + width = lineWidth; + } + } + + return width; + } + + public final int measureParagraphHeight(final String text, final int lineWidth, int leading) { + if (leading == 0) { + leading = this.baseline; + } + final int lineCount = this.breakLines(text, new int[]{lineWidth}, BROKEN_LINES); + return this.ascent + this.descent + leading * (lineCount - 1); + } + + public final String truncateWithEllipsisToFit(final String text, final int width) { + if (this.measureLineWidth(text) <= width) { + return text; + } else { + final int ellipsisWidth = this.measureLineWidth("..."); + final int availableWidth = width - ellipsisWidth; + int usedWidth = 0; + + for (int i = 0; i < text.length(); ++i) { + final int charWidth = this.getAdvanceWidth(text.charAt(i)); + if (usedWidth + charWidth > availableWidth) { + return text.substring(0, i - 1) + "..."; + } + + usedWidth += charWidth; + } + + return null; + } + } + + private void calculateJustifiedSpaceWidth(final String str, final int targetWidth) { + int spaceCount = 0; + boolean inEscape = false; + for (int i = 0; i < str.length(); ++i) { + final char c = str.charAt(i); + if (c == '<') { + inEscape = true; + } else if (c == '>') { + inEscape = false; + } else if (!inEscape && c == ' ') { + ++spaceCount; + } + } + + if (spaceCount > 0) { + spaceWidth = ((targetWidth - this.measureLineWidth(str)) << 8) / spaceCount; + } + } + // + + // + public final void draw(final String text, final int x, final int y, final int color) { + this.draw(text, x, y, color, Drawing.MAX_ALPHA); + } + + public final void draw(final String text, final int x, final int y, final int color, final int alpha) { + if (text != null) { + setFormattingParams(color, alpha); + this.executeDraw(text, x, y); + } + } + + public final void drawRightAligned(final String text, final int x, final int y, final int color) { + this.drawRightAligned(text, x, y, color, Drawing.MAX_ALPHA); + } + + public final void drawRightAligned(final String text, final int x, final int y, final int color, final int alpha) { + if (text != null) { + setFormattingParams(color, alpha); + this.executeDraw(text, x - this.measureLineWidth(text), y); + } + } + + public final void drawCentered(final String text, final int x, final int y, final int color) { + this.drawCentered(text, x, y, color, Drawing.MAX_ALPHA); + } + + public final void drawCentered(final String text, final int x, final int y, final int color, final int alpha) { + if (text != null) { + setFormattingParams(color, alpha); + this.executeDraw(text, x - this.measureLineWidth(text) / 2, y); + } + } + + public final void drawJustified(final String str, final int x, final int y, final int targetWidth) { + if (str != null) { + setFormattingParams(Drawing.WHITE); + this.calculateJustifiedSpaceWidth(str, targetWidth); + this.executeDraw(str, x, y); + } + } + + @SuppressWarnings("SameParameterValue") + public final void drawVertical(final String text, final int x, final int y, final int color) { + if (text != null) { + setFormattingParams(color); + this.executeDrawVertical(text, x, y); + } + } + + public final int drawParagraph(final String text, + final int x, + final int y, + final int width, + final int height, + final int color, + final @NotNull HorizontalAlignment horizontalAlignment, + final @NotNull VerticalAlignment verticalAlignment, + final int leading) { + return this.drawParagraph(text, x, y, width, height, color, 256, horizontalAlignment, verticalAlignment, leading); + } + + public final int drawParagraph(final String text, + final int x, + final int y, + final int width, + final int height, + final int color, + final int alpha, + final @NotNull HorizontalAlignment horizontalAlignment, + @NotNull VerticalAlignment verticalAlignment, + int leading) { + if (text == null) { + return 0; + } + + setFormattingParams(color, alpha); + if (leading == 0) { + leading = this.baseline; + } + + int[] var12 = new int[]{width}; + if (height < this.ascent + this.descent + leading && height < leading + leading) { + var12 = null; + } + + final int lineCount = this.breakLines(text, var12, BROKEN_LINES); + if (verticalAlignment == VerticalAlignment.DISTRIBUTE && lineCount == 1) { + verticalAlignment = VerticalAlignment.MIDDLE; + } + + int y1; + if (verticalAlignment == VerticalAlignment.TOP) { + y1 = y + this.ascent; + } else if (verticalAlignment == VerticalAlignment.MIDDLE) { + y1 = y + this.ascent + (height - this.ascent - this.descent - (lineCount - 1) * leading) / 2; + } else if (verticalAlignment == VerticalAlignment.BOTTOM) { + y1 = y + height - this.descent - (lineCount - 1) * leading; + } else { + final int var15 = Math.max((height - this.ascent - this.descent - (lineCount - 1) * leading) / (lineCount + 1), 0); + y1 = y + this.ascent + var15; + leading += var15; + } + + for (int i = 0; i < lineCount; ++i) { + if (horizontalAlignment == HorizontalAlignment.LEFT) { + this.executeDraw(BROKEN_LINES[i], x, y1); + } else if (horizontalAlignment == HorizontalAlignment.CENTER) { + this.executeDraw(BROKEN_LINES[i], x + (width - this.measureLineWidth(BROKEN_LINES[i])) / 2, y1); + } else if (horizontalAlignment == HorizontalAlignment.RIGHT) { + this.executeDraw(BROKEN_LINES[i], x + width - this.measureLineWidth(BROKEN_LINES[i]), y1); + } else if (i == lineCount - 1) { + this.executeDraw(BROKEN_LINES[i], x, y1); + } else { + this.calculateJustifiedSpaceWidth(BROKEN_LINES[i], width); + this.executeDraw(BROKEN_LINES[i], x, y1); + spaceWidth = 0; + } + + y1 += leading; + } + + return lineCount; + } + + protected abstract void drawGlyph(int index, int x, int y, int var4, int var5, int color, boolean var7); + protected abstract void drawGlyph(int index, int x, int y, int var4, int var5, int color, int alpha, boolean var8); + protected abstract void drawVerticalGlyph(int index, int x, int y, int height, int width, int color, boolean var7); + protected abstract void drawVerticalGlyph(int index, int x, int y, int height, int width, int color, int alpha, boolean var8); + + private static void setFormattingParams(final int color) { + setFormattingParams(color, 256); + } + + private static void setFormattingParams(final int color, final int alpha) { + setFormattingParams(color, -1, alpha); + } + + private static void setFormattingParams(final int color, final int shadowColor, final int alpha) { + strikethroughColor = -1; + underlineColor = -1; + globalShadowColor = shadowColor; + localShadowColor = shadowColor; + globalColor = color; + localColor = color; + globalAlpha = alpha; + localAlpha = alpha; + spaceWidth = 0; + spaceWidthError = 0; + } + + /** + * The {@link DrawExecutor} class extracts the common logic for drawing a + * line of text in an arbitrary orientation. + */ + private abstract class DrawExecutor { + abstract protected void drawGlyph(int index, int x, int y, int width, int height, int color, boolean var7); + abstract protected void drawGlyph(int index, int x, int y, int width, int height, int color, int alpha, boolean var8); + abstract protected int drawSymbol(int index, int x); + abstract protected void drawRule(int x, int y, int width, int color); + + @SuppressWarnings("WeakerAccess") + public final void execute(final String text) { + int x = 0; + int escapeStartPos = -1; + char lastGlyphIndex = 0; + for (int i = 0; i < text.length(); ++i) { + char glyphIndex = text.charAt(i); + if (glyphIndex == '<') { + escapeStartPos = i; + } else { + if (glyphIndex == '>' && escapeStartPos != -1) { + final String tag = text.substring(escapeStartPos + 1, i).toLowerCase(); + escapeStartPos = -1; + switch (tag) { + case "lt": + glyphIndex = '<'; + break; + case "gt": + break; + case "nbsp": + glyphIndex = 160; + break; + case "shy": + glyphIndex = 173; + break; + case "times": + glyphIndex = 215; + break; + case "euro": + glyphIndex = 8364; + break; + case "copy": + glyphIndex = 169; + break; + case "reg": + glyphIndex = 174; + break; + default: + if (tag.startsWith("img=")) { + x += this.drawSymbol(Strings.parseDecimalInteger(tag.substring(4)), x); + lastGlyphIndex = 0; + } else { + parseAttrTag(tag); + } + continue; + } + } + + if (escapeStartPos == -1) { + glyphIndex = (char) (Strings.encode1252Char(glyphIndex) & 255); + x += Font.this.getKerning(lastGlyphIndex, glyphIndex); + + final int inkWidth = Font.this.inkWidths[glyphIndex]; + final int inkHeight = Font.this.inkHeights[glyphIndex]; + final int startX = x; + if (glyphIndex != ' ') { + final int originX = Font.this.glyphOriginsX[glyphIndex]; + final int originY = Font.this.glyphOriginsY[glyphIndex]; + if (localAlpha == 256) { + if (localShadowColor != -1) { + this.drawGlyph(glyphIndex, x + originX + 1, originY + 1, inkWidth, inkHeight, localShadowColor, true); + } + this.drawGlyph(glyphIndex, x + originX, originY, inkWidth, inkHeight, localColor, false); + } else { + if (localShadowColor != -1) { + this.drawGlyph(glyphIndex, x + originX + 1, originY + 1, inkWidth, inkHeight, localShadowColor, localAlpha, true); + } + this.drawGlyph(glyphIndex, x + originX, originY, inkWidth, inkHeight, localColor, localAlpha, false); + } + } else if (spaceWidth > 0) { + spaceWidthError += spaceWidth; + x += spaceWidthError >> 8; + spaceWidthError &= 255; + } + + x += Font.this.advanceWidths[glyphIndex]; + if (strikethroughColor != -1) { + this.drawRule(startX, (int) ((double) Font.this.baseline * 0.7D), x - startX, strikethroughColor); + } + if (underlineColor != -1) { + this.drawRule(startX, Font.this.baseline + 1, x - startX, underlineColor); + } + + lastGlyphIndex = glyphIndex; + } + } + } + } + } + + private void executeDraw(final String text, final int x0, final int y0) { + new DrawExecutor() { + @Override + protected void drawGlyph(final int index, final int x, final int y, final int width, final int height, final int color, final boolean var7) { + Font.this.drawGlyph(index, x0 + x, y0 + y - Font.this.baseline, width, height, color, var7); + } + + @Override + protected void drawGlyph(final int index, final int x, final int y, final int width, final int height, final int color, final int alpha, final boolean var8) { + Font.this.drawGlyph(index, x0 + x, y0 + y - Font.this.baseline, width, height, color, alpha, var8); + } + + @Override + protected int drawSymbol(final int index, final int x) { + final Symbol symbol = Font.this.symbols[index]; + final int ascent = Font.this.symbolAscents != null ? Font.this.symbolAscents[index] : symbol.advanceY; + if (localAlpha == 256) { + symbol.draw(x0 + x, y0 - ascent); + } else { + symbol.draw(x0 + x, y0 - ascent, localAlpha); + } + return symbol.advanceX; + } + + @Override + protected void drawRule(final int x, final int y, final int width, final int color) { + Drawing.horizontalLine(x0 + x, y0 + y - Font.this.baseline, width, color); + } + }.execute(text); + } + + private void executeDrawVertical(final String text, final int x0, final int y0) { + new DrawExecutor() { + @Override + protected void drawGlyph(final int index, final int x, final int y, final int width, final int height, final int color, final boolean var7) { + Font.this.drawVerticalGlyph(index, x0 + y - Font.this.baseline, y0 - x - width, height, width, color, var7); + } + + @Override + protected void drawGlyph(final int index, final int x, final int y, final int width, final int height, final int color, final int alpha, final boolean var8) { + Font.this.drawVerticalGlyph(index, x0 + y - Font.this.baseline, y0 - x - width, height, width, color, alpha, var8); + } + + @Override + protected int drawSymbol(final int index, final int x) { + throw new UnsupportedOperationException("symbols are not supported in vertical drawing mode"); + } + + @Override + protected void drawRule(final int x, final int y, final int width, final int color) { + //noinspection SuspiciousNameCombination + Drawing.verticalLine(x0 + y - Font.this.baseline, y0 + x, width, color); + } + }.execute(text); + } + // + + // + private void parseMetrics(final byte[] metricsData) { + this.advanceWidths = new int[256]; + if (metricsData.length == 257) { + for (int i = 0; i < this.advanceWidths.length; ++i) { + this.advanceWidths[i] = metricsData[i] & 255; + } + this.baseline = metricsData[256] & 255; + } else { + int i = 0; + + for (int j = 0; j < 256; ++j) { + this.advanceWidths[j] = metricsData[i++] & 255; + } + + final int[] var10 = new int[256]; + for (int j = 0; j < 256; ++j) { + var10[j] = metricsData[i++] & 255; + } + final int[] var4 = new int[256]; + for (int j = 0; j < 256; ++j) { + var4[j] = metricsData[i++] & 255; + } + + final byte[][] var11 = new byte[256][]; + for (int j = 0; j < 256; ++j) { + var11[j] = new byte[var10[j]]; + byte var7 = 0; + + for (int k = 0; k < var11[j].length; ++k) { + var7 += metricsData[i++]; + var11[j][k] = var7; + } + } + + final byte[][] var12 = new byte[256][]; + + for (int j = 0; j < 256; ++j) { + var12[j] = new byte[var10[j]]; + byte var14 = 0; + + for (int k = 0; k < var12[j].length; ++k) { + var14 += metricsData[i++]; + var12[j][k] = var14; + } + } + + this.kerns = new byte[65536]; + + for (int glyph1 = 0; glyph1 < 256; ++glyph1) { + if (glyph1 != 32 && glyph1 != 160) { + for (int glyph2 = 0; glyph2 < 256; ++glyph2) { + if (glyph2 != 32 && glyph2 != 160) { + this.kerns[(glyph1 << 8) + glyph2] = (byte) calculateKerning(var11, var12, var4, this.advanceWidths, var10, glyph1, glyph2); + } + } + } + } + + this.baseline = var4[32] + var10[32]; + } + } + + private static int calculateKerning(final byte[][] var0, final byte[][] var1, final int[] var2, final int[] advanceWidths, final int[] var4, final int glyph1, final int glyph2) { + final int var7 = var2[glyph1]; + final int var8 = var7 + var4[glyph1]; + final int var9 = var2[glyph2]; + final int var10 = var9 + var4[glyph2]; + final int var11 = Math.max(var9, var7); + final int var12 = Math.min(var10, var8); + + int var13 = advanceWidths[glyph1]; + if (advanceWidths[glyph2] < var13) { + var13 = advanceWidths[glyph2]; + } + + final byte[] var14 = var1[glyph1]; + final byte[] var15 = var0[glyph2]; + int var16 = var11 - var7; + int var17 = var11 - var9; + + for (int var18 = var11; var18 < var12; ++var18) { + final int var19 = var14[var16++] + var15[var17++]; + if (var19 < var13) { + var13 = var19; + } + } + + return -var13; + } + // + + public enum HorizontalAlignment { + LEFT, + CENTER, + RIGHT, + JUSTIFY, + } + + public enum VerticalAlignment { + TOP, + MIDDLE, + BOTTOM, + DISTRIBUTE, + } +} diff --git a/src/main/java/funorb/graphics/NineSliceSprite.java b/src/main/java/funorb/graphics/NineSliceSprite.java new file mode 100644 index 0000000..4c668f4 --- /dev/null +++ b/src/main/java/funorb/graphics/NineSliceSprite.java @@ -0,0 +1,123 @@ +package funorb.graphics; + +@SuppressWarnings("WeakerAccess") +public final class NineSliceSprite { + public static final int TOP_LEFT = 0; + public static final int TOP = 1; + public static final int TOP_RIGHT = 2; + public static final int LEFT = 3; + public static final int CENTER = 4; + public static final int RIGHT = 5; + public static final int BOTTOM_LEFT = 6; + public static final int BOTTOM = 7; + public static final int BOTTOM_RIGHT = 8; + + private final Sprite[] patches; + + public NineSliceSprite(final Sprite[] var1) { + this.patches = var1; + } + + public static void draw(final Sprite[] patches, final int x, final int y, final int width, final int height) { + if (patches != null) { + if (width > 0 && height > 0) { + final int topOffset = patches[TOP] != null ? patches[TOP].offsetY : 0; + final int leftOffset = patches[LEFT] != null ? patches[LEFT].offsetX : 0; + final int rightOffset = patches[RIGHT] != null ? patches[RIGHT].offsetX : 0; + final int bottomOffset = patches[BOTTOM] != null ? patches[BOTTOM].offsetY : 0; + + final int right = x + width; + final int bottom = y + height; + + final int leftInsideX = x + leftOffset; + final int rightInsideX = right - rightOffset; + final int topInsideY = y + topOffset; + final int bottomInsideY = bottom - bottomOffset; + + int var16 = leftInsideX; + int var17 = rightInsideX; + if (leftInsideX > rightInsideX) { + var16 = var17 = x + ((width * leftOffset) / (rightOffset + leftOffset)); + } + + int var18 = topInsideY; + int var19 = bottomInsideY; + if (topInsideY > bottomInsideY) { + var18 = var19 = y + ((topOffset * height) / (topOffset + bottomOffset)); + } + + final int[] savedBounds = new int[4]; + Drawing.saveBoundsTo(savedBounds); + if (patches[TOP_LEFT] != null) { + Drawing.expandBoundsToInclude(x, y, var16, var18); + patches[TOP_LEFT].draw(x, y); + Drawing.restoreBoundsFrom(savedBounds); + } + + if (patches[TOP_RIGHT] != null) { + Drawing.expandBoundsToInclude(var17, y, right, var18); + patches[TOP_RIGHT].draw(rightInsideX, y); + Drawing.restoreBoundsFrom(savedBounds); + } + + if (patches[BOTTOM_LEFT] != null) { + Drawing.expandBoundsToInclude(x, var19, var16, bottom); + patches[BOTTOM_LEFT].draw(x, bottomInsideY); + Drawing.restoreBoundsFrom(savedBounds); + } + + if (patches[BOTTOM_RIGHT] != null) { + Drawing.expandBoundsToInclude(var17, var19, right, bottom); + patches[BOTTOM_RIGHT].draw(rightInsideX, bottomInsideY); + Drawing.restoreBoundsFrom(savedBounds); + } + + if (patches[TOP] != null && patches[TOP].offsetX != 0) { + Drawing.expandBoundsToInclude(var16, y, var17, var18); + for (int i = leftInsideX; i < rightInsideX; i += patches[TOP].offsetX) { + patches[TOP].draw(i, y); + } + Drawing.restoreBoundsFrom(savedBounds); + } + + if (patches[BOTTOM] != null && patches[BOTTOM].offsetX != 0) { + Drawing.expandBoundsToInclude(var16, var19, var17, bottom); + for (int i = leftInsideX; i < rightInsideX; i += patches[BOTTOM].offsetX) { + patches[BOTTOM].draw(i, bottomInsideY); + } + Drawing.restoreBoundsFrom(savedBounds); + } + + if (patches[LEFT] != null && patches[LEFT].offsetY != 0) { + Drawing.expandBoundsToInclude(x, var18, var16, var19); + for (int i = topInsideY; bottomInsideY > i; i += patches[LEFT].offsetY) { + patches[LEFT].draw(x, i); + } + Drawing.restoreBoundsFrom(savedBounds); + } + + if (patches[RIGHT] != null && patches[RIGHT].offsetY != 0) { + Drawing.expandBoundsToInclude(var17, var18, right, var19); + for (int i = topInsideY; i < bottomInsideY; i += patches[RIGHT].offsetY) { + patches[RIGHT].draw(rightInsideX, i); + } + Drawing.restoreBoundsFrom(savedBounds); + } + + if (patches[CENTER] != null && patches[CENTER].offsetX != 0 && patches[CENTER].offsetY != 0) { + Drawing.expandBoundsToInclude(var16, var18, var17, var19); + for (int i = topInsideY; i < bottomInsideY; i += patches[CENTER].offsetY) { + for (int j = leftInsideX; j < rightInsideX; j += patches[CENTER].offsetX) { + patches[CENTER].draw(j, i); + } + } + Drawing.restoreBoundsFrom(savedBounds); + } + } + } + } + + public void draw(final int var1, final int var2, final int var3, final int var4) { + draw(this.patches, var2, var3, var4, var1); + } +} diff --git a/src/main/java/funorb/graphics/PalettedSpriteFont.java b/src/main/java/funorb/graphics/PalettedSpriteFont.java new file mode 100644 index 0000000..d40c7b3 --- /dev/null +++ b/src/main/java/funorb/graphics/PalettedSpriteFont.java @@ -0,0 +1,298 @@ +package funorb.graphics; + +public final class PalettedSpriteFont extends Font { + private final byte[][] _H; + + public PalettedSpriteFont(final byte[] var1, final int[] xs, final int[] ys, final int[] widths, final int[] heights, final int[] palette, final byte[][] pixels) { + super(var1, xs, ys, widths, heights); + this._H = a675(palette, pixels); + } + + private static byte[][] a675(final int[] var0, final byte[][] var1) { + int var3; + for (int var2 = 0; var2 < var0.length; ++var2) { + var3 = var0[var2]; + final int var4 = (var3 >> 15 & 510) + (var3 & 255); + var0[var2] = var4 / 3 + (var3 >> 8 & 255) >> 1; + } + + for (var3 = 0; var3 < var1.length; ++var3) { + final byte[] var8 = var1[var3]; + + for (int var5 = 0; var5 < var8.length; ++var5) { + final byte var6 = var8[var5]; + if (var6 != 0) { + var8[var5] = (byte) var0[var6]; + } + } + } + + return var1; + } + + private static void b038(final int[] var0, final byte[] var1, final int var2, int var3, int var4, final int var5, final int var6, final int var7, final int var8, final int var9) { + for (int var10 = -var6; var10 < 0; ++var10) { + for (int var11 = -var5; var11 < 0; ++var11) { + int var12 = (255 & var1[var3++]) * var9 >> 8; + if (var12 == 0) { + ++var4; + } else { + final int var13 = ((var2 & 16711935) * var12 & -16711936) + ((var2 & '\uff00') * var12 & 16711680) >> 8; + var12 = 256 - var12; + final int var14 = var0[var4]; + var0[var4++] = (((var14 & 16711935) * var12 & -16711936) + ((var14 & '\uff00') * var12 & 16711680) >> 8) + var13; + } + } + + var4 += var7; + var3 += var8; + } + + } + + private static void a038(final int[] var0, final byte[] var1, final int var2, int var3, int var4, final int var5, final int var6, final int var7, final int var8, final int var9) { + for (int var10 = -var7; var10 < 0; ++var10) { + for (int var11 = -var6; var11 < 0; ++var11) { + int var12 = 255 & var1[var3]; + if (var12 == 0) { + ++var4; + } else { + final int var13 = ((var2 & 16711935) * var12 & -16711936) + ((var2 & '\uff00') * var12 & 16711680) >> 8; + var12 = 256 - var12; + final int var14 = var0[var4]; + var0[var4++] = (((var14 & 16711935) * var12 & -16711936) + ((var14 & '\uff00') * var12 & 16711680) >> 8) + var13; + } + + var3 += var5; + } + + var4 += var8; + var3 += var9; + } + + } + + private static void a111(final int[] var0, final byte[] var1, final int var2, int var3, int var4, final int var5, final int var6, final int var7, final int var8) { + for (int var9 = -var6; var9 < 0; ++var9) { + for (int var10 = -var5; var10 < 0; ++var10) { + int var11 = 255 & var1[var3++]; + if (var11 == 0) { + ++var4; + } else { + final int var12 = ((var2 & 16711935) * var11 & -16711936) + ((var2 & '\uff00') * var11 & 16711680) >> 8; + var11 = 256 - var11; + final int var13 = var0[var4]; + var0[var4++] = (((var13 & 16711935) * var11 & -16711936) + ((var13 & '\uff00') * var11 & 16711680) >> 8) + var12; + } + } + + var4 += var7; + var3 += var8; + } + } + + private static void a183(final int[] var0, final byte[] var1, final int var2, int var3, int var4, final int var5, final int var6, final int var7, final int var8, final int var9, final int var10) { + for (int var11 = -var7; var11 < 0; ++var11) { + for (int var12 = -var6; var12 < 0; ++var12) { + int var13 = (255 & var1[var3]) * var10 >> 8; + if (var13 == 0) { + ++var4; + } else { + final int var14 = ((var2 & 16711935) * var13 & -16711936) + ((var2 & '\uff00') * var13 & 16711680) >> 8; + var13 = 256 - var13; + final int var15 = var0[var4]; + var0[var4++] = (((var15 & 16711935) * var13 & -16711936) + ((var15 & '\uff00') * var13 & 16711680) >> 8) + var14; + } + + var3 += var5; + } + + var4 += var8; + var3 += var9; + } + + } + + @Override + public void drawGlyph(final int index, int x, int y, int var4, int var5, final int color, final boolean var7) { + int var8 = Drawing.pixelIndex(x, y); + int var9 = Drawing.width - var4; + int var10 = 0; + int var11 = 0; + int var12; + if (y < Drawing.top) { + var12 = Drawing.top - y; + var5 -= var12; + y = Drawing.top; + var11 += var12 * var4; + var8 += var12 * Drawing.width; + } + + if (y + var5 > Drawing.bottom) { + var5 -= y + var5 - Drawing.bottom; + } + + if (x < Drawing.left) { + var12 = Drawing.left - x; + var4 -= var12; + x = Drawing.left; + var11 += var12; + var8 += var12; + var10 += var12; + var9 += var12; + } + + if (x + var4 > Drawing.right) { + var12 = x + var4 - Drawing.right; + var4 -= var12; + var10 += var12; + var9 += var12; + } + + if (var4 > 0 && var5 > 0) { + if (var7) { + SpriteFont.a111(Drawing.screenBuffer, this._H[index], color, var11, var8, var4, var5, var9, var10); + } else { + a111(Drawing.screenBuffer, this._H[index], color, var11, var8, var4, var5, var9, var10); + } + } + } + + @Override + public void drawGlyph(final int index, int x, int y, int var4, int var5, final int color, final int alpha, final boolean var8) { + int var9 = Drawing.pixelIndex(x, y); + int var10 = Drawing.width - var4; + int var11 = 0; + int var12 = 0; + int var13; + if (y < Drawing.top) { + var13 = Drawing.top - y; + var5 -= var13; + y = Drawing.top; + var12 += var13 * var4; + var9 += var13 * Drawing.width; + } + + if (y + var5 > Drawing.bottom) { + var5 -= y + var5 - Drawing.bottom; + } + + if (x < Drawing.left) { + var13 = Drawing.left - x; + var4 -= var13; + x = Drawing.left; + var12 += var13; + var9 += var13; + var11 += var13; + var10 += var13; + } + + if (x + var4 > Drawing.right) { + var13 = x + var4 - Drawing.right; + var4 -= var13; + var11 += var13; + var10 += var13; + } + + if (var4 > 0 && var5 > 0) { + if (var8) { + SpriteFont.b038(Drawing.screenBuffer, this._H[index], color, var12, var9, var4, var5, var10, var11, alpha); + } else { + b038(Drawing.screenBuffer, this._H[index], color, var12, var9, var4, var5, var10, var11, alpha); + } + + } + } + + @Override + public void drawVerticalGlyph(final int index, int x, int y, int height, int width, final int color, final int alpha, final boolean var8) { + int var9 = Drawing.pixelIndex(x, y); + int var10 = Drawing.width - height; + final int var11 = width; + final byte var12 = -1; + int var13 = width - 1; + int var14; + if (y < Drawing.top) { + var14 = Drawing.top - y; + width -= var14; + y = Drawing.top; + var13 -= var14; + var9 += var14 * Drawing.width; + } + + if (y + width > Drawing.bottom) { + width -= y + width - Drawing.bottom; + } + + if (x < Drawing.left) { + var14 = Drawing.left - x; + height -= var14; + x = Drawing.left; + var13 += var14 * var11; + var9 += var14; + var10 += var14; + } + + if (x + height > Drawing.right) { + var14 = x + height - Drawing.right; + height -= var14; + var10 += var14; + } + + if (height > 0 && width > 0) { + final int var15 = var12 - var11 * height; + if (var8) { + SpriteFont.a183(Drawing.screenBuffer, this._H[index], color, var13, var9, var11, height, width, var10, var15, alpha); + } else { + a183(Drawing.screenBuffer, this._H[index], color, var13, var9, var11, height, width, var10, var15, alpha); + } + + } + } + + @Override + public void drawVerticalGlyph(final int index, int x, int y, int height, int width, final int color, final boolean var7) { + int var8 = Drawing.pixelIndex(x, y); + int var9 = Drawing.width - height; + final int var10 = width; + final byte var11 = -1; + int var12 = width - 1; + int var13; + if (y < Drawing.top) { + var13 = Drawing.top - y; + width -= var13; + y = Drawing.top; + var12 -= var13; + var8 += var13 * Drawing.width; + } + + if (y + width > Drawing.bottom) { + width -= y + width - Drawing.bottom; + } + + if (x < Drawing.left) { + var13 = Drawing.left - x; + height -= var13; + x = Drawing.left; + var12 += var13 * var10; + var8 += var13; + var9 += var13; + } + + if (x + height > Drawing.right) { + var13 = x + height - Drawing.right; + height -= var13; + var9 += var13; + } + + if (height > 0 && width > 0) { + final int var14 = var11 - var10 * height; + if (var7) { + SpriteFont.a038(Drawing.screenBuffer, this._H[index], color, var12, var8, var10, height, width, var9, var14); + } else { + a038(Drawing.screenBuffer, this._H[index], color, var12, var8, var10, height, width, var9, var14); + } + + } + } +} diff --git a/src/main/java/funorb/graphics/PalettedSymbol.java b/src/main/java/funorb/graphics/PalettedSymbol.java new file mode 100644 index 0000000..3995100 --- /dev/null +++ b/src/main/java/funorb/graphics/PalettedSymbol.java @@ -0,0 +1,189 @@ +package funorb.graphics; + +public final class PalettedSymbol extends Symbol { + public byte[] pixels; + public int[] palette; + + public PalettedSymbol(final int offsetX, final int offsetY, final int x, final int y, final int width, final int height, final byte[] pixels, final int[] palette) { + this.advanceX = offsetX; + this.advanceY = offsetY; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.pixels = pixels; + this.palette = palette; + } + + public PalettedSymbol() { + this.advanceX = this.width = 0; + this.advanceY = this.height = 0; + this.y = 0; + this.x = 0; + this.pixels = new byte[0]; + this.palette = new int[0]; + } + + private static void b723(final int[] var0, final byte[] var1, final int[] var2, int var4, int var5, int var6, final int var7, final int var8, final int var9) { + final int var10 = -(var6 >> 2); + var6 = -(var6 & 3); + + for (int var11 = -var7; var11 < 0; ++var11) { + int var12; + byte var13; + for (var12 = var10; var12 < 0; ++var12) { + var13 = var1[var4++]; + if (var13 == 0) { + ++var5; + } else { + var0[var5++] = var2[var13 & 255]; + } + + var13 = var1[var4++]; + if (var13 == 0) { + ++var5; + } else { + var0[var5++] = var2[var13 & 255]; + } + + var13 = var1[var4++]; + if (var13 == 0) { + ++var5; + } else { + var0[var5++] = var2[var13 & 255]; + } + + var13 = var1[var4++]; + if (var13 == 0) { + ++var5; + } else { + var0[var5++] = var2[var13 & 255]; + } + } + + for (var12 = var6; var12 < 0; ++var12) { + var13 = var1[var4++]; + if (var13 == 0) { + ++var5; + } else { + var0[var5++] = var2[var13 & 255]; + } + } + + var5 += var8; + var4 += var9; + } + + } + + private static void a723(final int[] buffer, final byte[] pixels, final int[] palette, int var3, int var4, final int var5, final int var6, final int var7, final int var8, final int alpha) { + final int var10 = 256 - alpha; + + for (int var11 = -var6; var11 < 0; ++var11) { + for (int var12 = -var5; var12 < 0; ++var12) { + final byte var13 = pixels[var3++]; + if (var13 == 0) { + ++var4; + } else { + final int var15 = palette[var13 & 255]; + final int var14 = buffer[var4]; + buffer[var4++] = ((var15 & 0xff00ff) * alpha + (var14 & 0xff00ff) * var10 & 0xff00ff00) + ((var15 & 0xff00) * alpha + (var14 & 0xff00) * var10 & 0xff0000) >> 8; + } + } + + var4 += var7; + var3 += var8; + } + + } + + @Override + public void draw(int x, int y) { + x += this.x; + y += this.y; + int var3 = Drawing.pixelIndex(x, y); + int var4 = 0; + int var5 = this.height; + int var6 = this.width; + int var7 = Drawing.width - var6; + int var8 = 0; + int var9; + if (y < Drawing.top) { + var9 = Drawing.top - y; + var5 -= var9; + y = Drawing.top; + var4 += var9 * var6; + var3 += var9 * Drawing.width; + } + + if (y + var5 > Drawing.bottom) { + var5 -= y + var5 - Drawing.bottom; + } + + if (x < Drawing.left) { + var9 = Drawing.left - x; + var6 -= var9; + x = Drawing.left; + var4 += var9; + var3 += var9; + var8 += var9; + var7 += var9; + } + + if (x + var6 > Drawing.right) { + var9 = x + var6 - Drawing.right; + var6 -= var9; + var8 += var9; + var7 += var9; + } + + if (var6 > 0 && var5 > 0) { + b723(Drawing.screenBuffer, this.pixels, this.palette, var4, var3, var6, var5, var7, var8); + } + } + + @Override + public void draw(int x, int y, final int alpha) { + x += this.x; + y += this.y; + int var4 = Drawing.pixelIndex(x, y); + int var5 = 0; + int var6 = this.height; + int var7 = this.width; + int var8 = Drawing.width - var7; + int var9 = 0; + int var10; + if (y < Drawing.top) { + var10 = Drawing.top - y; + var6 -= var10; + y = Drawing.top; + var5 += var10 * var7; + var4 += var10 * Drawing.width; + } + + if (y + var6 > Drawing.bottom) { + var6 -= y + var6 - Drawing.bottom; + } + + if (x < Drawing.left) { + var10 = Drawing.left - x; + var7 -= var10; + x = Drawing.left; + var5 += var10; + var4 += var10; + var9 += var10; + var8 += var10; + } + + if (x + var7 > Drawing.right) { + var10 = x + var7 - Drawing.right; + var7 -= var10; + var9 += var10; + var8 += var10; + } + + if (var7 > 0 && var6 > 0) { + a723(Drawing.screenBuffer, this.pixels, this.palette, var5, var4, var7, var6, var8, var9, alpha); + } + } +} diff --git a/src/main/java/funorb/graphics/Point.java b/src/main/java/funorb/graphics/Point.java new file mode 100644 index 0000000..93e660f --- /dev/null +++ b/src/main/java/funorb/graphics/Point.java @@ -0,0 +1,11 @@ +package funorb.graphics; + +public final class Point { + public final int x; + public final int y; + + public Point(final int x, final int y) { + this.x = x; + this.y = y; + } +} diff --git a/src/main/java/funorb/graphics/Rect.java b/src/main/java/funorb/graphics/Rect.java new file mode 100644 index 0000000..fb88cc5 --- /dev/null +++ b/src/main/java/funorb/graphics/Rect.java @@ -0,0 +1,28 @@ +package funorb.graphics; + +import org.jetbrains.annotations.Contract; + +public final class Rect { + public int y1; + public int x1; + public int x2; + public int y2; + + @Contract(pure = true) + public Rect() { + this(0, 0, 0, 0); + } + + @Contract(pure = true) + public Rect(final int x1, final int y1, final int x2, final int y2) { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } + + public boolean contains(final int x, final int y) { + return x >= this.x1 && x < this.x2 + && y >= this.y1 && y < this.y2; + } +} diff --git a/src/main/java/funorb/graphics/Sprite.java b/src/main/java/funorb/graphics/Sprite.java new file mode 100644 index 0000000..c0a67d2 --- /dev/null +++ b/src/main/java/funorb/graphics/Sprite.java @@ -0,0 +1,2153 @@ +package funorb.graphics; + +import java.awt.Component; +import java.awt.Image; +import java.awt.MediaTracker; +import java.awt.Toolkit; +import java.awt.image.PixelGrabber; + +public class Sprite { + public int x; + public int y; + public int width; + public int height; + public int offsetX; + public int offsetY; + public int[] pixels; + + public Sprite(final int offsetX, final int offsetY, final int x, final int y, final int width, final int height, final int[] pixels) { + this.offsetX = offsetX; + this.offsetY = offsetY; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.pixels = pixels; + } + + public Sprite(final int var1, final int var2) { + this.pixels = new int[var1 * var2]; + this.width = this.offsetX = var1; + this.height = this.offsetY = var2; + this.y = 0; + this.x = 0; + } + + public Sprite(final byte[] imageData, final Component canvas) { + try { + final Image image = Toolkit.getDefaultToolkit().createImage(imageData); + final MediaTracker tracker = new MediaTracker(canvas); + tracker.addImage(image, 0); + tracker.waitForAll(); + this.width = image.getWidth(canvas); + this.height = image.getHeight(canvas); + this.offsetX = this.width; + this.offsetY = this.height; + this.x = 0; + this.y = 0; + this.pixels = new int[this.width * this.height]; + new PixelGrabber(image, 0, 0, this.width, this.height, this.pixels, 0, this.width).grabPixels(); + } catch (final InterruptedException var6) { + } + } + + private static void compositeOverTinted(final int[] src, final int srcStride, int srcPos, final int[] dest, final int destStride, int destPos, final int cols, final int rows, final int color) { + final int r1 = (color >> 16) & 255; + final int g1 = (color >> 8) & 255; + final int b1 = color & 255; + final int var14 = (-(cols >> 2) << 2) - (cols & 3); + + for (int i = 0; i < rows; ++i) { + for (int j = var14; j < 0; ++j) { + final int srcColor = src[srcPos++]; + if (srcColor != 0) { + final int r2 = (srcColor >> 16) & 255; + final int g2 = (srcColor >> 8) & 255; + final int b2 = srcColor & 255; + if (r2 == g2 && g2 == b2) { + final int r3; + final int g3; + final int b3; + if (r2 <= 128) { + r3 = ((r2 * r1) >> 7) << 16; + g3 = ((g2 * g1) >> 7) << 8; + b3 = (b2 * b1) >> 7; + } else { + r3 = (((r1 * (256 - r2)) + (255 * (r2 - 128))) >> 7) << 16; + g3 = (((g1 * (256 - g2)) + (255 * (g2 - 128))) >> 7) << 8; + b3 = ((b1 * (256 - b2)) + (255 * (b2 - 128))) >> 7; + } + dest[destPos] = r3 + g3 + b3; + } else { + dest[destPos] = srcColor; + } + } + destPos++; + } + + destPos += destStride; + srcPos += srcStride; + } + } + + private static void a543(int var3, final int[] var4, final int[] var5, int var8, int var9, int var10, final int var11, final int var12, final int var13, final int var14, final int var15) { + for (final int var16 = var3; var8 < 0; ++var8) { + final int var7 = (var9 >> 16) * var15; + + int var6; + for (var6 = -var12; var6 < 0; ++var6) { + int var0 = var4[(var3 >> 16) + var7]; + if (var0 == 0) { + ++var10; + } else { + final int var1 = var5[var10]; + final int var2 = var0 + var1; + var0 = (var0 & 16711935) + (var1 & 16711935); + final int i = (var0 & 16777472) + (var2 - var0 & 65536); + var5[var10++] = var2 - i | i - (i >>> 8); + } + + var3 += var13; + } + + var9 += var14; + var3 = var16; + var10 += var11; + } + + } + + protected void compositeOver(final int[] src, final int srcStride, int srcPos, final int[] dest, final int destStride, int destPos, final int cols, final int rows) { + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + final int color = src[srcPos++]; + if (color == 0) { + ++destPos; + } else { + dest[destPos++] = color; + } + } + + srcPos += srcStride; + destPos += destStride; + } + } + + private static void compositeOver(final int[] src, final int srcStride, int srcPos, final int[] dest, final int destStride, int destPos, final int cols, final int rows, final int alpha) { + final int alpha2 = 256 - alpha; + + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + final int srcColor = src[srcPos++]; + if (srcColor == 0) { + ++destPos; + } else { + final int destColor = dest[destPos]; + final int rb = (((srcColor & 0xff00ff) * alpha) + ((destColor & 0xff00ff) * alpha2)) & 0xff00ff00; + final int g = (((srcColor & 0x00ff00) * alpha) + ((destColor & 0x00ff00) * alpha2)) & 0xff0000; + dest[destPos++] = (rb + g) >> 8; + } + } + + destPos += destStride; + srcPos += srcStride; + } + } + + private static void compositeAdd(final int[] src, final int srcStride, int srcPos, final int[] dest, final int destStride, int destPos, final int cols, final int rows, final int alpha) { + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + final int srcColor = src[srcPos++]; + if (srcColor != 0) { + dest[destPos] = Drawing.saturatingAdd(srcColor, dest[destPos], alpha); + } + destPos++; + } + + destPos += destStride; + srcPos += srcStride; + } + } + + private static void compositeAdd(final int[] src, final int srcStride, int srcPos, final int[] dest, final int destStride, int destPos, final int cols, final int rows) { + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + final int srcColor = src[srcPos++]; + if (srcColor != 0) { + dest[destPos] = Drawing.saturatingAdd(srcColor, dest[destPos]); + } + destPos++; + } + + destPos += destStride; + srcPos += srcStride; + } + } + + private static void a871(final int[] var1, final int[] var2, int var4, int var5, final int var6, final int var7, final int var8, final int var9) { + for (int var10 = -var7; var10 < 0; ++var10) { + for (int var11 = -var6; var11 < 0; ++var11) { + final int var3 = var2[var4++]; + if (var3 == 0) { + ++var5; + } else { + final int var0 = var1[var5]; + if (var0 == 0) { + ++var5; + } else { + final int var12 = ((var3 & 16711680) >>> 16) * ((var0 & 16711680) >>> 16) >>> 8; + final int var13 = (var3 & '\uff00') * (var0 & '\uff00') >>> 24; + final int var14 = (var3 & 255) * (var0 & 255) >>> 8; + var1[var5++] = (var12 << 16) + (var13 << 8) + var14; + } + } + } + + var5 += var8; + var4 += var9; + } + + } + + private static void a600(final int[] var0, int var1, int var2, final int var3, final int var4, final int var5, final int var6, final int var7) { + for (int var8 = 0; var8 < var7; var2 += var4) { + for (int var9 = 0; var9 < var6; var1 += 2) { + final int var11 = Drawing.screenBuffer[var2] & 16711935; + final int var12 = Drawing.screenBuffer[var2] & '\uff00'; + final byte var13 = 0; + final byte var14 = 0; + int var10; + int var15; + int var16; + if ((var10 = var0[var1]) == 0) { + var15 = var13 + var11; + var16 = var14 + var12; + } else { + var15 = var13 + (var10 & 16711935); + var16 = var14 + (var10 & '\uff00'); + } + + if ((var10 = var0[var1 + 1]) == 0) { + var15 += var11; + var16 += var12; + } else { + var15 += var10 & 16711935; + var16 += var10 & '\uff00'; + } + + if ((var10 = var0[var1 + var5]) == 0) { + var15 += var11; + var16 += var12; + } else { + var15 += var10 & 16711935; + var16 += var10 & '\uff00'; + } + + if ((var10 = var0[var1 + var5 + 1]) == 0) { + var15 += var11; + var16 += var12; + } else { + var15 += var10 & 16711935; + var16 += var10 & '\uff00'; + } + + Drawing.screenBuffer[var2++] = (var15 & 66847740 | var16 & 261120) >> 2; + ++var9; + } + + ++var8; + var1 += var3; + } + + } + + private static void compositeOverTinted2(final int[] src, final int srcStride, int srcPos, final int[] dest, final int destStride, int destPos, final int cols, final int rows, final int color) { + final int rb1 = color & 0xff00ff; + final int g1 = (color >> 8) & 255; + + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + final int color2 = src[srcPos++]; + if (color2 != 0) { + if ((color2 >> 8) == (color2 & 0x00ffff)) { + final int g2 = color2 & 255; + dest[destPos] = (((g2 * rb1) >> 8) & 0xff00fe) + ((g2 * g1) & 0x00ff00) + 1; + } else { + dest[destPos] = color2; + } + } + destPos++; + } + + destPos += destStride; + srcPos += srcStride; + } + } + + private static void a590(final int[] var0, final int[] var1, int var3, int var4, int var5, final int var6, final int var7, final int var8, final int var9, final int var10, final int var11, final int var12) { + final int var13 = 256 - var12; + final int var14 = var3; + + for (int var15 = -var8; var15 < 0; ++var15) { + final int var16 = (var4 >> 16) * var11; + + for (int var17 = -var7; var17 < 0; ++var17) { + final int var2 = var1[(var3 >> 16) + var16]; + if (var2 == 0) { + ++var5; + } else { + final int var18 = var0[var5]; + var0[var5++] = ((var2 & 16711935) * var12 + (var18 & 16711935) * var13 & -16711936) + ((var2 & '\uff00') * var12 + (var18 & '\uff00') * var13 & 16711680) >> 8; + } + + var3 += var9; + } + + var4 += var10; + var3 = var14; + var5 += var6; + } + + } + + private static void b983(final int[] var0, final int[] var1, int var3, int var4, int var5, final int var6, final int var7, final int var8, final int var9, final int var10, final int var11) { + final int var12 = var3; + + for (int var13 = -var8; var13 < 0; ++var13) { + final int var14 = (var4 >> 16) * var11; + + for (int var15 = -var7; var15 < 0; ++var15) { + final int var2 = var1[(var3 >> 16) + var14]; + if (var2 == 0) { + ++var5; + } else { + var0[var5++] = var2; + } + + var3 += var9; + } + + var4 += var10; + var3 = var12; + var5 += var6; + } + + } + + private static void a134(int var3, final int[] var4, final int[] var5, int var8, int var9, int var10, final int var11, final int var12, final int var13, final int var14, final int var15, final int var16) { + for (final int var17 = var3; var8 < 0; ++var8) { + final int var7 = (var9 >> 16) * var15; + + int var6; + for (var6 = -var12; var6 < 0; ++var6) { + int var0 = var4[(var3 >> 16) + var7]; + if (var0 == 0) { + ++var10; + } else { + final int var1 = (var0 & 16711935) * var16; + var0 = (var1 & -16711936) + (var0 * var16 - var1 & 16711680) >>> 8; + final int i = var5[var10]; + final int var2 = var0 + i; + var0 = (var0 & 16711935) + (i & 16711935); + final int i1 = (var0 & 16777472) + (var2 - var0 & 65536); + var5[var10++] = var2 - i1 | i1 - (i1 >>> 8); + } + + var3 += var13; + } + + var9 += var14; + var3 = var17; + var10 += var11; + } + + } + + private static void a415(final int[] dest, final int[] src, int srcPos, int destPos, final int var4, final int var5, final int var6, final int var7) { + for (int i = 0; i < var5; ++i) { + final int var9 = destPos + var4; + while (destPos < var9) { + dest[destPos++] = src[srcPos++]; + } + destPos += var6; + srcPos += var7; + } + } + + private static void b650(final int[] var0, final int[] var1, final int var2, int var3, int var4, int var5, final int var6, final int var7, final int var8) { + final int var9 = -(var5 >> 2); + var5 = -(var5 & 3); + + for (int var10 = -var6; var10 < 0; ++var10) { + int var11; + for (var11 = var9; var11 < 0; ++var11) { + if (var1[var3++] == 0) { + ++var4; + } else { + var0[var4++] = var2; + } + + if (var1[var3++] == 0) { + ++var4; + } else { + var0[var4++] = var2; + } + + if (var1[var3++] == 0) { + ++var4; + } else { + var0[var4++] = var2; + } + + if (var1[var3++] == 0) { + ++var4; + } else { + var0[var4++] = var2; + } + } + + for (var11 = var5; var11 < 0; ++var11) { + if (var1[var3++] == 0) { + ++var4; + } else { + var0[var4++] = var2; + } + } + + var4 += var7; + var3 += var8; + } + + } + + public final void d797() { + int var1 = 0; + int var2 = this.width * this.height; + + int var10001; + final int[] var3; + for (var3 = new int[var2]; var2 > 0; var3[var10001] = this.pixels[var2]) { + var10001 = var1++; + --var2; + } + + this.pixels = var3; + this.x = this.offsetX - this.width - this.x; + this.y = this.offsetY - this.height - this.y; + } + + public void draw(int x, int y, final int alpha) { + x += this.x; + y += this.y; + int rows = this.height; + int cols = this.width; + int srcPos = 0; + int srcStride = 0; + int destPos = Drawing.pixelIndex(x, y); + int destStride = Drawing.width - cols; + if (y < Drawing.top) { + final int clippedRows = Drawing.top - y; + y = Drawing.top; + rows -= clippedRows; + srcPos += clippedRows * this.width; + destPos += clippedRows * Drawing.width; + } + if (rows > Drawing.bottom - y) { + rows = Drawing.bottom - y; + } + + if (x < Drawing.left) { + final int clippedCols = Drawing.left - x; + x = Drawing.left; + cols -= clippedCols; + srcPos += clippedCols; + destPos += clippedCols; + srcStride += clippedCols; + destStride += clippedCols; + } + if (cols > Drawing.right - x) { + final int clippedCols = cols - (Drawing.right - x); + cols -= clippedCols; + srcStride += clippedCols; + destStride += clippedCols; + } + + if (cols > 0 && rows > 0) { + compositeOver(this.pixels, srcStride, srcPos, Drawing.screenBuffer, destStride, destPos, cols, rows, alpha); + } + } + + public void a669(int var1, int var2, final int var3, final int var4, final int var5, final int var6) { + if (var6 != 0) { + var1 -= this.x << 4; + var2 -= this.y << 4; + final double var7 = (double) (var5 & '\uffff') * 9.587379924285257E-5D; + final int var9 = (int) Math.floor(Math.sin(var7) * (double) var6 + 0.5D); + final int var10 = (int) Math.floor(Math.cos(var7) * (double) var6 + 0.5D); + final int var11 = -var1 * var10 + -var2 * var9; + final int var12 = -(-var1) * var9 + -var2 * var10; + final int var13 = ((this.width << 4) - var1) * var10 + -var2 * var9; + final int var14 = -((this.width << 4) - var1) * var9 + -var2 * var10; + final int var15 = -var1 * var10 + ((this.height << 4) - var2) * var9; + final int var16 = -(-var1) * var9 + ((this.height << 4) - var2) * var10; + final int var17 = ((this.width << 4) - var1) * var10 + ((this.height << 4) - var2) * var9; + final int var18 = -((this.width << 4) - var1) * var9 + ((this.height << 4) - var2) * var10; + int var19; + int var20; + if (var11 < var13) { + var19 = var11; + var20 = var13; + } else { + var19 = var13; + var20 = var11; + } + + if (var15 < var19) { + var19 = var15; + } + + if (var17 < var19) { + var19 = var17; + } + + if (var15 > var20) { + var20 = var15; + } + + if (var17 > var20) { + var20 = var17; + } + + int var21; + int var22; + if (var12 < var14) { + var21 = var12; + var22 = var14; + } else { + var21 = var14; + var22 = var12; + } + + if (var16 < var21) { + var21 = var16; + } + + if (var18 < var21) { + var21 = var18; + } + + if (var16 > var22) { + var22 = var16; + } + + if (var18 > var22) { + var22 = var18; + } + + var19 >>= 12; + var20 = var20 + 4095 >> 12; + var21 >>= 12; + var22 = var22 + 4095 >> 12; + var19 += var3; + var20 += var3; + var21 += var4; + var22 += var4; + var19 >>= 4; + var20 = var20 + 15 >> 4; + var21 >>= 4; + var22 = var22 + 15 >> 4; + if (var19 < Drawing.left) { + var19 = Drawing.left; + } + + if (var20 > Drawing.right) { + var20 = Drawing.right; + } + + if (var21 < Drawing.top) { + var21 = Drawing.top; + } + + if (var22 > Drawing.bottom) { + var22 = Drawing.bottom; + } + + var20 = var19 - var20; + if (var20 < 0) { + var22 = var21 - var22; + if (var22 < 0) { + int var23 = var21 * Drawing.width + var19; + final double var24 = 1.6777216E7D / (double) var6; + final int var26 = (int) Math.floor(Math.sin(var7) * var24 + 0.5D); + final int var27 = (int) Math.floor(Math.cos(var7) * var24 + 0.5D); + final int var28 = (var19 << 4) + 8 - var3; + final int var29 = (var21 << 4) + 8 - var4; + int var30 = (var1 << 8) - (var29 * var26 >> 4); + int var31 = (var2 << 8) + (var29 * var27 >> 4); + int var32; + int var33; + int var34; + int var35; + int var36; + int var37; + int var38; + if (var27 == 0) { + if (var26 == 0) { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30; + var36 = var31; + var37 = var20; + if (var30 >= 0 && var31 >= 0 && var30 - (this.width << 12) < 0 && var31 - (this.height << 12) < 0) { + for (; var37 < 0; ++var37) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + if (var38 == 0) { + ++var34; + } else { + Drawing.screenBuffer[var34++] = var38; + } + } + } + + ++var33; + } + } else if (var26 < 0) { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30; + var36 = var31 + (var28 * var26 >> 4); + var37 = var20; + if (var30 >= 0 && var30 - (this.width << 12) < 0) { + if ((var32 = var36 - (this.height << 12)) >= 0) { + var32 = (var26 - var32) / var26; + var37 = var20 + var32; + var36 += var26 * var32; + var34 = var23 + var32; + } + + if ((var32 = (var36 - var26) / var26) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + if (var38 == 0) { + ++var34; + } else { + Drawing.screenBuffer[var34++] = var38; + } + + var36 += var26; + ++var37; + } + } + + ++var33; + var30 -= var26; + } + } else { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30; + var36 = var31 + (var28 * var26 >> 4); + var37 = var20; + if (var30 >= 0 && var30 - (this.width << 12) < 0) { + if (var36 < 0) { + var32 = (var26 - 1 - var36) / var26; + var37 = var20 + var32; + var36 += var26 * var32; + var34 = var23 + var32; + } + + if ((var32 = (1 + var36 - (this.height << 12) - var26) / var26) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + if (var38 == 0) { + ++var34; + } else { + Drawing.screenBuffer[var34++] = var38; + } + + var36 += var26; + ++var37; + } + } + + ++var33; + var30 -= var26; + } + } + } else if (var27 < 0) { + if (var26 == 0) { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30 + (var28 * var27 >> 4); + var36 = var31; + var37 = var20; + if (var31 >= 0 && var31 - (this.height << 12) < 0) { + if ((var32 = var35 - (this.width << 12)) >= 0) { + var32 = (var27 - var32) / var27; + var37 = var20 + var32; + var35 += var27 * var32; + var34 = var23 + var32; + } + + if ((var32 = (var35 - var27) / var27) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + if (var38 == 0) { + ++var34; + } else { + Drawing.screenBuffer[var34++] = var38; + } + + var35 += var27; + ++var37; + } + } + + ++var33; + var31 += var27; + } + } else if (var26 < 0) { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30 + (var28 * var27 >> 4); + var36 = var31 + (var28 * var26 >> 4); + var37 = var20; + if ((var32 = var35 - (this.width << 12)) >= 0) { + var32 = (var27 - var32) / var27; + var37 = var20 + var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 = var23 + var32; + } + + if ((var32 = (var35 - var27) / var27) > var37) { + var37 = var32; + } + + if ((var32 = var36 - (this.height << 12)) >= 0) { + var32 = (var26 - var32) / var26; + var37 += var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 += var32; + } + + if ((var32 = (var36 - var26) / var26) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + if (var38 == 0) { + ++var34; + } else { + Drawing.screenBuffer[var34++] = var38; + } + + var35 += var27; + var36 += var26; + ++var37; + } + + ++var33; + var30 -= var26; + var31 += var27; + } + } else { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30 + (var28 * var27 >> 4); + var36 = var31 + (var28 * var26 >> 4); + var37 = var20; + if ((var32 = var35 - (this.width << 12)) >= 0) { + var32 = (var27 - var32) / var27; + var37 = var20 + var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 = var23 + var32; + } + + if ((var32 = (var35 - var27) / var27) > var37) { + var37 = var32; + } + + if (var36 < 0) { + var32 = (var26 - 1 - var36) / var26; + var37 += var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 += var32; + } + + if ((var32 = (1 + var36 - (this.height << 12) - var26) / var26) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + if (var38 == 0) { + ++var34; + } else { + Drawing.screenBuffer[var34++] = var38; + } + + var35 += var27; + var36 += var26; + ++var37; + } + + ++var33; + var30 -= var26; + var31 += var27; + } + } + } else if (var26 == 0) { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30 + (var28 * var27 >> 4); + var36 = var31; + var37 = var20; + if (var31 >= 0 && var31 - (this.height << 12) < 0) { + if (var35 < 0) { + var32 = (var27 - 1 - var35) / var27; + var37 = var20 + var32; + var35 += var27 * var32; + var34 = var23 + var32; + } + + if ((var32 = (1 + var35 - (this.width << 12) - var27) / var27) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + if (var38 == 0) { + ++var34; + } else { + Drawing.screenBuffer[var34++] = var38; + } + + var35 += var27; + ++var37; + } + } + + ++var33; + var31 += var27; + } + } else if (var26 < 0) { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30 + (var28 * var27 >> 4); + var36 = var31 + (var28 * var26 >> 4); + var37 = var20; + if (var35 < 0) { + var32 = (var27 - 1 - var35) / var27; + var37 = var20 + var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 = var23 + var32; + } + + if ((var32 = (1 + var35 - (this.width << 12) - var27) / var27) > var37) { + var37 = var32; + } + + if ((var32 = var36 - (this.height << 12)) >= 0) { + var32 = (var26 - var32) / var26; + var37 += var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 += var32; + } + + if ((var32 = (var36 - var26) / var26) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + if (var38 == 0) { + ++var34; + } else { + Drawing.screenBuffer[var34++] = var38; + } + + var35 += var27; + var36 += var26; + ++var37; + } + + ++var33; + var30 -= var26; + var31 += var27; + } + } else { + for (var33 = var22; var33 < 0; var23 += Drawing.width) { + var34 = var23; + var35 = var30 + (var28 * var27 >> 4); + var36 = var31 + (var28 * var26 >> 4); + var37 = var20; + if (var35 < 0) { + var32 = (var27 - 1 - var35) / var27; + var37 = var20 + var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 = var23 + var32; + } + + if ((var32 = (1 + var35 - (this.width << 12) - var27) / var27) > var37) { + var37 = var32; + } + + if (var36 < 0) { + var32 = (var26 - 1 - var36) / var26; + var37 += var32; + var35 += var27 * var32; + var36 += var26 * var32; + var34 += var32; + } + + if ((var32 = (1 + var36 - (this.height << 12) - var26) / var26) > var37) { + var37 = var32; + } + + while (var37 < 0) { + var38 = this.pixels[(var36 >> 12) * this.width + (var35 >> 12)]; + if (var38 == 0) { + ++var34; + } else { + Drawing.screenBuffer[var34++] = var38; + } + + var35 += var27; + var36 += var26; + ++var37; + } + + ++var33; + var30 -= var26; + var31 += var27; + } + } + + } + } + } + } + + public final void e093() { + int var1 = 0; + int var2 = 0; + var1 += this.x; + var2 += this.y; + int var3 = Drawing.pixelIndex(var1, var2); + int var4 = 0; + int var5 = this.height; + int var6 = this.width; + int var7 = Drawing.width - var6; + int var8 = 0; + int var9; + if (var2 < Drawing.top) { + var9 = Drawing.top - var2; + var5 -= var9; + var2 = Drawing.top; + var4 += var9 * var6; + var3 += var9 * Drawing.width; + } + + if (var2 + var5 > Drawing.bottom) { + var5 -= var2 + var5 - Drawing.bottom; + } + + if (var1 < Drawing.left) { + var9 = Drawing.left - var1; + var6 -= var9; + var1 = Drawing.left; + var4 += var9; + var3 += var9; + var8 += var9; + var7 += var9; + } + + if (var1 + var6 > Drawing.right) { + var9 = var1 + var6 - Drawing.right; + var6 -= var9; + var8 += var9; + var7 += var9; + } + + if (var6 > 0 && var5 > 0) { + a871(Drawing.screenBuffer, this.pixels, var4, var3, var6, var5, var7, var8); + } + } + + public void drawTinted(int x, int y, final int color) { + x += this.x; + y += this.y; + int rows = this.height; + int cols = this.width; + int srcPos = 0; + int srcStride = 0; + int destPos = Drawing.pixelIndex(x, y); + int destStride = Drawing.width - cols; + if (y < Drawing.top) { + final int clippedRows = Drawing.top - y; + y = Drawing.top; + rows -= clippedRows; + srcPos += clippedRows * this.width; + destPos += clippedRows * Drawing.width; + } + if (rows > Drawing.bottom - y) { + rows = Drawing.bottom - y; + } + + if (x < Drawing.left) { + final int clippedCols = Drawing.left - x; + x = Drawing.left; + cols -= clippedCols; + srcPos += clippedCols; + destPos += clippedCols; + srcStride += clippedCols; + destStride += clippedCols; + } + if (cols > Drawing.right - x) { + final int clippedCols = cols - (Drawing.right - x); + cols -= clippedCols; + srcStride += clippedCols; + destStride += clippedCols; + } + + if (cols > 0 && rows > 0) { + compositeOverTinted(this.pixels, srcStride, srcPos, Drawing.screenBuffer, destStride, destPos, cols, rows, color); + } + } + + public final void b797() { + final int[] var1 = this.pixels; + + for (int var2 = (this.height >> 1) - 1; var2 >= 0; --var2) { + int var3 = var2 * this.width; + int var4 = (this.height - var2 - 1) * this.width; + + for (int var5 = -this.width; var5 < 0; ++var5) { + final int var6 = var1[var3]; + var1[var3] = var1[var4]; + var1[var4] = var6; + ++var3; + ++var4; + } + } + + this.y = this.offsetY - this.height - this.y; + } + + private void d050(final int var1, final int var2, final int var3, final int var4a, final int var5a) { + final int var6 = var3 * this.width + var2; + final int var4 = var4a & 0x0fff; + final int var5 = var5a & 0x0fff; + final int var7; + final int var8; + int var11; + int var12; + if (var3 >= 0) { + if (var2 >= 0) { + var7 = this.pixels[var6]; + var11 = var7 != 0 ? (4096 - var4) * (4096 - var5) : 0; + } else { + var11 = 0; + var7 = 0; + } + + if (var2 < this.width - 1) { + var8 = this.pixels[var6 + 1]; + var12 = var8 != 0 ? var4 * (4096 - var5) : 0; + } else { + var12 = 0; + var8 = 0; + } + } else { + var12 = 0; + var11 = 0; + var8 = 0; + var7 = 0; + } + + final int var9; + final int var10; + int var13; + int var14; + if (var3 < this.height - 1) { + if (var2 >= 0) { + var9 = this.pixels[var6 + this.width]; + var13 = var9 != 0 ? (4096 - var4) * var5 : 0; + } else { + var13 = 0; + var9 = 0; + } + + if (var2 < this.width - 1) { + var10 = this.pixels[var6 + this.width + 1]; + var14 = var10 != 0 ? var4 * var5 : 0; + } else { + var14 = 0; + var10 = 0; + } + } else { + var14 = 0; + var13 = 0; + var10 = 0; + var9 = 0; + } + + var11 >>= 16; + var12 >>= 16; + var13 >>= 16; + var14 >>= 16; + final int var15 = var11 + var12 + var13 + var14; + final int i1 = (var7 & 0xff00ff) * var11 + (var8 & 0xff00ff) * var12 + ((var9 & 0xff00ff) * var13 + (var10 & 0xff00ff) * var14); + final int i2 = (var7 & 0x00ff00) * var11 + (var8 & 0x00ff00) * var12 + ((var9 & 0x00ff00) * var13 + (var10 & 0x00ff00) * var14); + if (var15 >= 256) { + int var18 = (i1 >>> 8 & 0xff00ff) + (i2 >>> 8 & 0x00ff00); + if (var18 == 0) { + var18 = 1; + } + + Drawing.screenBuffer[var1] = var18; + } else if (var15 >= 128) { + int var18 = ((i1 >>> 16) / var15 << 16) + (i2 / var15 & 0x00ff00) + (i1 & 0x00ffff) / var15; + if (var18 == 0) { + var18 = 1; + } + + Drawing.screenBuffer[var1] = var18; + } + } + + public final void f797() { + final int[] pixels = new int[this.width * this.height]; + int i = 0; + for (int x = 0; x < this.width; ++x) { + for (int y = this.height - 1; y >= 0; --y) { + pixels[i++] = this.pixels[x + y * this.width]; + } + } + this.pixels = pixels; + + final int tmp1 = this.y; + //noinspection SuspiciousNameCombination + this.y = this.x; + this.x = this.offsetY - this.height - tmp1; + + final int tmp2 = this.height; + //noinspection SuspiciousNameCombination + this.height = this.width; + this.width = tmp2; + + final int tmp3 = this.offsetY; + //noinspection SuspiciousNameCombination + this.offsetY = this.offsetX; + this.offsetX = tmp3; + } + + public void drawAdd(int x, int y, final int alpha) { + x += this.x; + y += this.y; + int rows = this.height; + int cols = this.width; + int srcPos = 0; + int srcStride = 0; + int destPos = Drawing.pixelIndex(x, y); + int destStride = Drawing.width - cols; + if (y < Drawing.top) { + final int clippedRows = Drawing.top - y; + y = Drawing.top; + rows -= clippedRows; + srcPos += clippedRows * this.width; + destPos += clippedRows * Drawing.width; + } + if (rows > Drawing.bottom - y) { + rows = Drawing.bottom - y; + } + + if (x < Drawing.left) { + final int clippedCols = Drawing.left - x; + x = Drawing.left; + cols -= clippedCols; + srcPos += clippedCols; + destPos += clippedCols; + srcStride += clippedCols; + destStride += clippedCols; + } + if (cols > Drawing.right - x) { + final int clippedCols = cols - (Drawing.right - x); + cols -= clippedCols; + srcStride += clippedCols; + destStride += clippedCols; + } + + if (cols > 0 && rows > 0) { + if (alpha == 256) { + compositeAdd(this.pixels, srcStride, srcPos, Drawing.screenBuffer, destStride, destPos, cols, rows); + } else { + compositeAdd(this.pixels, srcStride, srcPos, Drawing.screenBuffer, destStride, destPos, cols, rows, alpha); + } + } + } + + public final void draw(int x, int y) { + x += this.x; + y += this.y; + int rows = this.height; + int cols = this.width; + int srcPos = 0; + int srcStride = 0; + int destPos = Drawing.pixelIndex(x, y); + int destStride = Drawing.width - cols; + + if (y < Drawing.top) { + final int clippedRows = Drawing.top - y; + y = Drawing.top; + rows -= clippedRows; + srcPos += clippedRows * this.width; + destPos += clippedRows * Drawing.width; + } + + if (y + rows > Drawing.bottom) { + rows -= y + rows - Drawing.bottom; + } + + if (x < Drawing.left) { + final int clippedCols = Drawing.left - x; + x = Drawing.left; + cols -= clippedCols; + srcPos += clippedCols; + destPos += clippedCols; + srcStride += clippedCols; + destStride += clippedCols; + } + + if (x + cols > Drawing.right) { + final int clippedCols = x + cols - Drawing.right; + cols -= clippedCols; + srcStride += clippedCols; + destStride += clippedCols; + } + + if (cols > 0 && rows > 0) { + this.compositeOver(this.pixels, srcStride, srcPos, Drawing.screenBuffer, destStride, destPos, cols, rows); + } + } + + public final Sprite horizontallyFlipped() { + final Sprite sprite = new Sprite(this.width, this.height); + sprite.offsetX = this.offsetX; + sprite.offsetY = this.offsetY; + sprite.x = this.offsetX - this.width - this.x; + sprite.y = this.y; + + for (int y = 0; y < this.height; ++y) { + for (int x = 0; x < this.width; ++x) { + sprite.pixels[(y * this.width) + x] = this.pixels[(y * this.width) + this.width - x - 1]; + } + } + + return sprite; + } + + public final void e326(int var1, int var2, final int var3) { + var1 += this.x; + var2 += this.y; + int var4 = Drawing.pixelIndex(var1, var2); + int var5 = 0; + int var6 = this.height; + int var7 = this.width; + int var8 = Drawing.width - var7; + int var9 = 0; + int var10; + if (var2 < Drawing.top) { + var10 = Drawing.top - var2; + var6 -= var10; + var2 = Drawing.top; + var5 += var10 * var7; + var4 += var10 * Drawing.width; + } + + if (var2 + var6 > Drawing.bottom) { + var6 -= var2 + var6 - Drawing.bottom; + } + + if (var1 < Drawing.left) { + var10 = Drawing.left - var1; + var7 -= var10; + var1 = Drawing.left; + var5 += var10; + var4 += var10; + var9 += var10; + var8 += var10; + } + + if (var1 + var7 > Drawing.right) { + var10 = var1 + var7 - Drawing.right; + var7 -= var10; + var9 += var10; + var8 += var10; + } + + if (var7 > 0 && var6 > 0) { + b650(Drawing.screenBuffer, this.pixels, var3, var5, var4, var7, var6, var8, var9); + } + } + + public void d093(int var1, int var2) { + var1 += this.x >> 1; + var2 += this.y >> 1; + final int var3 = var1 < Drawing.left ? Drawing.left - var1 << 1 : 0; + final int var4 = var1 + (this.width >> 1) > Drawing.right ? Drawing.right - var1 << 1 : this.width; + final int var5 = var2 < Drawing.top ? Drawing.top - var2 << 1 : 0; + final int var6 = var2 + (this.height >> 1) > Drawing.bottom ? Drawing.bottom - var2 << 1 : this.height; + a600(this.pixels, var5 * this.width + var3, (var2 + (var5 >> 1)) * Drawing.width + var1 + (var3 >> 1), (this.width << 1) - (var4 - var3) + (this.width & 1), Drawing.width - (var4 - var3 >> 1), this.width, var4 - var3 >> 1, var6 - var5 >> 1); + } + + public final void a115(final int var3) { + int var1 = 40; + int var2 = 40; + final int var5 = this.offsetX << 3; + final int var6 = this.offsetY << 3; + var1 = (var1 << 4) + (var5 & 15); + var2 = (var2 << 4) + (var6 & 15); + this.b669(var5, var6, var1, var2, var3, 16384); + } + + public void b115(int x, int y, int width, int height) { + if (width > 0 && height > 0) { + final int var5 = this.width; + final int var6 = this.height; + int var7 = 0; + int var8 = 0; + final int var9 = this.offsetX; + final int var10 = this.offsetY; + final int var11 = (var9 << 16) / width; + final int var12 = (var10 << 16) / height; + int var13; + if (this.x > 0) { + var13 = ((this.x << 16) + var11 - 1) / var11; + x += var13; + var7 += var13 * var11 - (this.x << 16); + } + + if (this.y > 0) { + var13 = ((this.y << 16) + var12 - 1) / var12; + y += var13; + var8 += var13 * var12 - (this.y << 16); + } + + if (var5 < var9) { + width = ((var5 << 16) - var7 + var11 - 1) / var11; + } + + if (var6 < var10) { + height = ((var6 << 16) - var8 + var12 - 1) / var12; + } + + var13 = Drawing.pixelIndex(x, y); + int var14 = Drawing.width - width; + if (y + height > Drawing.bottom) { + height -= y + height - Drawing.bottom; + } + + int var15; + if (y < Drawing.top) { + var15 = Drawing.top - y; + height -= var15; + var13 += var15 * Drawing.width; + var8 += var12 * var15; + } + + if (x + width > Drawing.right) { + var15 = x + width - Drawing.right; + width -= var15; + var14 += var15; + } + + if (x < Drawing.left) { + var15 = Drawing.left - x; + width -= var15; + var13 += var15; + var7 += var11 * var15; + var14 += var15; + } + + b983(Drawing.screenBuffer, this.pixels, var7, var8, var13, var14, width, height, var11, var12, var5); + } + } + + public final void installForDrawing() { + Drawing.initialize(this.pixels, this.width, this.height); + } + + public final void withInstalledForDrawing(final Runnable action) { + Drawing.withLocalContext(() -> { + this.installForDrawing(); + action.run(); + }); + } + + public final void withInstalledForDrawingUsingOffsets(final Runnable action) { + Drawing.withLocalContext(() -> { + Drawing.initialize(this.pixels, this.offsetX, this.offsetY); + action.run(); + }); + } + + public final void c115(final int var1, final int var2, final int var3, final int var4) { + if (var3 <= this.offsetX && var4 <= this.offsetY) { + int var5 = var1 + this.x * var3 / this.offsetX; + int var6 = var1 + ((this.x + this.width) * var3 + this.offsetX - 1) / this.offsetX; + int var7 = var2 + this.y * var4 / this.offsetY; + int var8 = var2 + ((this.y + this.height) * var4 + this.offsetY - 1) / this.offsetY; + if (var5 < Drawing.left) { + var5 = Drawing.left; + } + + if (var6 > Drawing.right) { + var6 = Drawing.right; + } + + if (var7 < Drawing.top) { + var7 = Drawing.top; + } + + if (var8 > Drawing.bottom) { + var8 = Drawing.bottom; + } + + if (var5 < var6 && var7 < var8) { + int var9 = var7 * Drawing.width + var5; + final int var10 = Drawing.width - (var6 - var5); + + for (int var11 = var7; var11 < var8; ++var11) { + for (int var12 = var5; var12 < var6; ++var12) { + final int var13 = var12 - var1 << 4; + final int var14 = var11 - var2 << 4; + int var15 = var13 * this.offsetX / var3 - (this.x << 4); + int var16 = (var13 + 16) * this.offsetX / var3 - (this.x << 4); + int var17 = var14 * this.offsetY / var4 - (this.y << 4); + int var18 = (var14 + 16) * this.offsetY / var4 - (this.y << 4); + final int var19 = (var16 - var15) * (var18 - var17); + if (var19 != 0) { + if (var15 < 0) { + var15 = 0; + } + + if (var16 > this.width << 4) { + var16 = this.width << 4; + } + + if (var17 < 0) { + var17 = 0; + } + + if (var18 > this.height << 4) { + var18 = this.height << 4; + } + + --var16; + --var18; + final int var20 = 16 - (var15 & 15); + final int var21 = (var16 & 15) + 1; + final int var22 = 16 - (var17 & 15); + final int var23 = (var18 & 15) + 1; + var15 >>= 4; + var16 >>= 4; + var17 >>= 4; + var18 >>= 4; + int var24 = 0; + int var25 = 0; + int var26 = 0; + int var27 = 0; + final int var28 = Drawing.screenBuffer[var9]; + + int var29; + for (var29 = var17; var29 <= var18; ++var29) { + int var30 = 16; + if (var29 == var17) { + var30 = var22; + } + + if (var29 == var18) { + var30 = var23; + } + + for (int var31 = var15; var31 <= var16; ++var31) { + int var32 = this.pixels[var29 * this.width + var31]; + if (var32 == 0) { + var32 = var28; + } + + final int var33; + if (var31 == var15) { + var33 = var30 * var20; + } else if (var31 == var16) { + var33 = var30 * var21; + } else { + var33 = var30 << 4; + } + + var27 += var33; + var24 += (var32 >> 16 & 255) * var33; + var25 += (var32 >> 8 & 255) * var33; + var26 += (var32 & 255) * var33; + } + } + + if (var27 < var19) { + var29 = var19 - var27; + var24 += (var28 >> 16 & 255) * var29; + var25 += (var28 >> 8 & 255) * var29; + var26 += (var28 & 255) * var29; + } + + var29 = (var24 / var19 << 16) + (var25 / var19 << 8) + var26 / var19; + if (var29 == 0) { + var29 = 1; + } + + Drawing.screenBuffer[var9] = var29; + ++var9; + } + } + + var9 += var10; + } + + } + } else { + throw new IllegalArgumentException(); + } + } + + public void b050(int var1, int var2, int var3, int var4, final int var5) { + if (var3 > 0 && var4 > 0) { + final int var6 = this.width; + final int var7 = this.height; + int var8 = 0; + int var9 = 0; + final int var10 = this.offsetX; + final int var11 = this.offsetY; + final int var12 = (var10 << 16) / var3; + final int var13 = (var11 << 16) / var4; + int var14; + if (this.x > 0) { + var14 = ((this.x << 16) + var12 - 1) / var12; + var1 += var14; + var8 += var14 * var12 - (this.x << 16); + } + + if (this.y > 0) { + var14 = ((this.y << 16) + var13 - 1) / var13; + var2 += var14; + var9 += var14 * var13 - (this.y << 16); + } + + if (var6 < var10) { + var3 = ((var6 << 16) - var8 + var12 - 1) / var12; + } + + if (var7 < var11) { + var4 = ((var7 << 16) - var9 + var13 - 1) / var13; + } + + var14 = Drawing.pixelIndex(var1, var2); + int var15 = Drawing.width - var3; + if (var2 + var4 > Drawing.bottom) { + var4 -= var2 + var4 - Drawing.bottom; + } + + int var16; + if (var2 < Drawing.top) { + var16 = Drawing.top - var2; + var4 -= var16; + var14 += var16 * Drawing.width; + var9 += var13 * var16; + } + + if (var1 + var3 > Drawing.right) { + var16 = var1 + var3 - Drawing.right; + var3 -= var16; + var15 += var16; + } + + if (var1 < Drawing.left) { + var16 = Drawing.left - var1; + var3 -= var16; + var14 += var16; + var8 += var12 * var16; + var15 += var16; + } + + a590(Drawing.screenBuffer, this.pixels, var8, var9, var14, var15, var3, var4, var12, var13, var6, var5); + } + } + + public final void b669(int var1, int var2, final int var3, final int var4, final int var5, final int var6) { + if (var6 != 0) { + var1 -= this.x << 4; + var2 -= this.y << 4; + final double var7 = (double) (var5 & '\uffff') * 9.587379924285257E-5D; + final int var9 = (int) Math.floor(Math.sin(var7) * (double) var6 + 0.5D); + final int var10 = (int) Math.floor(Math.cos(var7) * (double) var6 + 0.5D); + final int var11 = -var1 * var10 + -var2 * var9; + final int var12 = -(-var1) * var9 + -var2 * var10; + final int var13 = ((this.width << 4) - var1) * var10 + -var2 * var9; + final int var14 = -((this.width << 4) - var1) * var9 + -var2 * var10; + final int var15 = -var1 * var10 + ((this.height << 4) - var2) * var9; + final int var16 = -(-var1) * var9 + ((this.height << 4) - var2) * var10; + final int var17 = ((this.width << 4) - var1) * var10 + ((this.height << 4) - var2) * var9; + final int var18 = -((this.width << 4) - var1) * var9 + ((this.height << 4) - var2) * var10; + int var19; + int var20; + if (var11 < var13) { + var19 = var11; + var20 = var13; + } else { + var19 = var13; + var20 = var11; + } + + if (var15 < var19) { + var19 = var15; + } + + if (var17 < var19) { + var19 = var17; + } + + if (var15 > var20) { + var20 = var15; + } + + if (var17 > var20) { + var20 = var17; + } + + int var21; + int var22; + if (var12 < var14) { + var21 = var12; + var22 = var14; + } else { + var21 = var14; + var22 = var12; + } + + if (var16 < var21) { + var21 = var16; + } + + if (var18 < var21) { + var21 = var18; + } + + if (var16 > var22) { + var22 = var16; + } + + if (var18 > var22) { + var22 = var18; + } + + var19 >>= 12; + var20 = var20 + 4095 >> 12; + var21 >>= 12; + var22 = var22 + 4095 >> 12; + var19 += var3; + var20 += var3; + var21 += var4; + var22 += var4; + var19 >>= 4; + var20 = var20 + 15 >> 4; + var21 >>= 4; + var22 = var22 + 15 >> 4; + if (var19 < Drawing.left) { + var19 = Drawing.left; + } + + if (var20 > Drawing.right) { + var20 = Drawing.right; + } + + if (var21 < Drawing.top) { + var21 = Drawing.top; + } + + if (var22 > Drawing.bottom) { + var22 = Drawing.bottom; + } + + var20 = var19 - var20; + if (var20 < 0) { + var22 = var21 - var22; + if (var22 < 0) { + int var23 = var21 * Drawing.width + var19; + final int var24 = Drawing.width + var20; + final double var25 = 1.6777216E7D / (double) var6; + final int var27 = (int) Math.floor(Math.sin(var7) * var25 + 0.5D); + final int var28 = (int) Math.floor(Math.cos(var7) * var25 + 0.5D); + final int var29 = (var19 << 4) + 8 - var3; + final int var30 = (var21 << 4) + 8 - var4; + int var31 = (var1 << 8) - 2048 - (var30 * var27 >> 4); + int var32 = (var2 << 8) - 2048 + (var30 * var28 >> 4); + int var33; + int var34; + int var35; + int var36; + int var37; + int var38; + int var39; + if (var28 < 0) { + if (var27 < 0) { + for (var36 = var22; var36 < 0; var23 += var24) { + { + var37 = var31 + (var29 * var28 >> 4); + var38 = var32 + (var29 * var27 >> 4); + var39 = var20; + if ((var35 = var37 - (this.width << 12)) >= 0) { + + var35 = (var28 - var35) / var28; + var39 = var20 + var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + if ((var35 = var38 - (this.height << 12)) >= 0) { + + var35 = (var27 - var35) / var27; + var39 += var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + while (var39 < 0 && var37 >= -4096 && var38 >= -4096) { + var33 = var37 >> 12; + var34 = var38 >> 12; + this.d050(var23, var33, var34, var37, var38); + ++var39; + var37 += var28; + var38 += var27; + ++var23; + } + + var23 -= var39; + } + + ++var36; + var31 -= var27; + var32 += var28; + } + } else { + for (var36 = var22; var36 < 0; var23 += var24) { + label252: + { + var37 = var31 + (var29 * var28 >> 4); + var38 = var32 + (var29 * var27 >> 4); + var39 = var20; + if ((var35 = var37 - (this.width << 12)) >= 0) { + + var35 = (var28 - var35) / var28; + var39 = var20 + var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + if ((var35 = var38 + 4096) < 0) { + if (var27 == 0) { + var23 -= var39; + break label252; + } + + var35 = (var27 - 1 - var35) / var27; + var39 += var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + while (var39 < 0 && var37 >= -4096 && (var34 = var38 >> 12) < this.height) { + var33 = var37 >> 12; + this.d050(var23, var33, var34, var37, var38); + ++var39; + var37 += var28; + var38 += var27; + ++var23; + } + + var23 -= var39; + } + + ++var36; + var31 -= var27; + var32 += var28; + } + } + } else if (var27 < 0) { + for (var36 = var22; var36 < 0; var23 += var24) { + label254: + { + var37 = var31 + (var29 * var28 >> 4); + var38 = var32 + (var29 * var27 >> 4); + var39 = var20; + if ((var35 = var37 + 4096) < 0) { + if (var28 == 0) { + var23 -= var20; + break label254; + } + + var35 = (var28 - 1 - var35) / var28; + var39 = var20 + var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + if ((var35 = var38 - (this.height << 12)) >= 0) { + + var35 = (var27 - var35) / var27; + var39 += var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + while (var39 < 0 && var38 >= -4096 && (var33 = var37 >> 12) < this.width) { + var34 = var38 >> 12; + this.d050(var23, var33, var34, var37, var38); + ++var39; + var37 += var28; + var38 += var27; + ++var23; + } + + var23 -= var39; + } + + ++var36; + var31 -= var27; + var32 += var28; + } + } else { + for (var36 = var22; var36 < 0; var23 += var24) { + label256: + { + var37 = var31 + (var29 * var28 >> 4); + var38 = var32 + (var29 * var27 >> 4); + var39 = var20; + if ((var35 = var37 + 4096) < 0) { + if (var28 == 0) { + var23 -= var20; + break label256; + } + + var35 = (var28 - 1 - var35) / var28; + var39 = var20 + var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + if ((var35 = var38 + 4096) < 0) { + if (var27 == 0) { + var23 -= var39; + break label256; + } + + var35 = (var27 - 1 - var35) / var27; + var39 += var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + while (var39 < 0 && (var33 = var37 >> 12) < this.width && (var34 = var38 >> 12) < this.height) { + this.d050(var23, var33, var34, var37, var38); + ++var39; + var37 += var28; + var38 += var27; + ++var23; + } + + var23 -= var39; + } + + ++var36; + var31 -= var27; + var32 += var28; + } + } + + } + } + } + } + + public final void c050(int var1, int var2, int var3, int var4, final int var5) { + if (var3 > 0 && var4 > 0) { + final int var6 = this.width; + final int var7 = this.height; + int var8 = 0; + int var9 = 0; + final int var10 = this.offsetX; + final int var11 = this.offsetY; + final int var12 = (var10 << 16) / var3; + final int var13 = (var11 << 16) / var4; + int var14; + if (this.x > 0) { + var14 = ((this.x << 16) + var12 - 1) / var12; + var1 += var14; + var8 += var14 * var12 - (this.x << 16); + } + + if (this.y > 0) { + var14 = ((this.y << 16) + var13 - 1) / var13; + var2 += var14; + var9 += var14 * var13 - (this.y << 16); + } + + if (var6 < var10) { + var3 = ((var6 << 16) - var8 + var12 - 1) / var12; + } + + if (var7 < var11) { + var4 = ((var7 << 16) - var9 + var13 - 1) / var13; + } + + var14 = Drawing.pixelIndex(var1, var2); + int var15 = Drawing.width - var3; + if (var2 + var4 > Drawing.bottom) { + var4 -= var2 + var4 - Drawing.bottom; + } + + int var16; + if (var2 < Drawing.top) { + var16 = Drawing.top - var2; + var4 -= var16; + var14 += var16 * Drawing.width; + var9 += var13 * var16; + } + + if (var1 + var3 > Drawing.right) { + var16 = var1 + var3 - Drawing.right; + var3 -= var16; + var15 += var16; + } + + if (var1 < Drawing.left) { + var16 = Drawing.left - var1; + var3 -= var16; + var14 += var16; + var8 += var12 * var16; + var15 += var16; + } + + if (var5 == 256) { + a543(var8, this.pixels, Drawing.screenBuffer, -var4, var9, var14, var15, var3, var12, var13, var6); + } else { + a134(var8, this.pixels, Drawing.screenBuffer, -var4, var9, var14, var15, var3, var12, var13, var6, var5); + } + + } + } + + public void drawTinted2(int x, int y, final int color) { + x += this.x; + y += this.y; + int rows = this.height; + int cols = this.width; + int srcPos = 0; + int srcStride = 0; + int destPos = Drawing.pixelIndex(x, y); + int destStride = Drawing.width - cols; + if (y < Drawing.top) { + final int clippedRows = Drawing.top - y; + y = Drawing.top; + rows -= clippedRows; + srcPos += clippedRows * this.width; + destPos += clippedRows * Drawing.width; + } + if (rows > Drawing.bottom - y) { + rows = Drawing.bottom - y; + } + + if (x < Drawing.left) { + final int clippedCols = Drawing.left - x; + x = Drawing.left; + cols -= clippedCols; + srcPos += clippedCols; + destPos += clippedCols; + srcStride += clippedCols; + destStride += clippedCols; + } + if (cols > Drawing.right - x) { + final int clippedCols = cols - (Drawing.right - x); + cols -= clippedCols; + srcStride += clippedCols; + destStride += clippedCols; + } + + if (cols > 0 && rows > 0) { + compositeOverTinted2(this.pixels, srcStride, srcPos, Drawing.screenBuffer, destStride, destPos, cols, rows, color); + } + } + + public Sprite copy() { + final Sprite sprite = new Sprite(this.width, this.height); + sprite.offsetX = this.offsetX; + sprite.offsetY = this.offsetY; + sprite.x = this.x; + sprite.y = this.y; + System.arraycopy(this.pixels, 0, sprite.pixels, 0, this.pixels.length); + return sprite; + } + + public void g093() { + int var1 = 0; + int var2 = 0; + final int var3 = this.width >> 2; + final int var4 = this.height >> 2; + var1 += this.x / 4; + var2 += this.y / 4; + final int var5 = var1 < Drawing.left ? Drawing.left - var1 << 2 : 0; + final int var6 = var1 + var3 > Drawing.right ? (Drawing.right - var1 << 2) - 4 : this.width - 4; + final int var7 = var2 < Drawing.top ? Drawing.top - var2 << 2 : 0; + final int var8 = var2 + var4 > Drawing.bottom ? (Drawing.bottom - var2 << 2) - 4 : this.height - 4; + + for (int var9 = var7; var9 <= var8; var9 += 4) { + int var10 = var9 * this.width + var5; + int var11 = (var2 + (var9 >> 2)) * Drawing.width + var1 + (var5 >> 2); + + for (int var12 = var5; var12 <= var6; ++var11) { + int var14 = 0; + int var15 = 0; + + for (int var16 = 0; var16 < 4; ++var16) { + for (int var17 = 0; var17 < 4; ++var17) { + int var18 = this.pixels[var10 + var16 * this.width + var17]; + if (var18 == 0) { + var18 = Drawing.screenBuffer[var11]; + } + + var14 += var18 & 16711935; + var15 += var18 & '\uff00'; + } + } + + Drawing.screenBuffer[var11] = (var14 & 267390960 | var15 & 1044480) >> 4; + var12 += 4; + var10 += 4; + } + } + } + + public void c093(int x, int y) { + x += this.x; + y += this.y; + int var3 = Drawing.pixelIndex(x, y); + int var4 = 0; + int var5 = this.height; + int var6 = this.width; + int var7 = Drawing.width - var6; + int var8 = 0; + int var9; + if (y < Drawing.top) { + var9 = Drawing.top - y; + var5 -= var9; + y = Drawing.top; + var4 += var9 * var6; + var3 += var9 * Drawing.width; + } + + if (y + var5 > Drawing.bottom) { + var5 -= y + var5 - Drawing.bottom; + } + + if (x < Drawing.left) { + var9 = Drawing.left - x; + var6 -= var9; + x = Drawing.left; + var4 += var9; + var3 += var9; + var8 += var9; + var7 += var9; + } + + if (x + var6 > Drawing.right) { + var9 = x + var6 - Drawing.right; + var6 -= var9; + var8 += var9; + var7 += var9; + } + + if (var6 > 0 && var5 > 0) { + a415(Drawing.screenBuffer, this.pixels, var4, var3, var6, var5, var7, var8); + } + } + + public final void flipHorizontal() { + for (int i = this.height - 1; i >= 0; --i) { + int k = (i + 1) * this.width; + for (int j = i * this.width; j < k; ++j) { + --k; + final int tmp = this.pixels[j]; + this.pixels[j] = this.pixels[k]; + this.pixels[k] = tmp; + } + } + this.x = this.offsetX - this.width - this.x; + } + + public final void f150(final int var1) { + final int[] var2 = new int[this.width * this.height]; + int var3 = 0; + + for (int var4 = 0; var4 < this.height; ++var4) { + for (int var5 = 0; var5 < this.width; ++var5) { + int var6 = this.pixels[var3]; + if (var6 == 0) { + if (var5 > 0 && this.pixels[var3 - 1] != 0) { + var6 = var1; + } else if (var4 > 0 && this.pixels[var3 - this.width] != 0) { + var6 = var1; + } else if (var5 < this.width - 1 && this.pixels[var3 + 1] != 0) { + var6 = var1; + } else if (var4 < this.height - 1 && this.pixels[var3 + this.width] != 0) { + var6 = var1; + } + } + + var2[var3++] = var6; + } + } + + this.pixels = var2; + } + + public final void a050(int var2, final int var3, int var4, final int var5) { + final int var6 = this.offsetX << 3; + final int var7 = this.offsetY << 3; + var4 = (var4 << 4) + (var6 & 15); + var2 = (var2 << 4) + (15 & var7); + this.a669(var6, var7, var4, var2, var5, var3); + } +} diff --git a/src/main/java/funorb/graphics/SpriteFont.java b/src/main/java/funorb/graphics/SpriteFont.java new file mode 100644 index 0000000..9be417f --- /dev/null +++ b/src/main/java/funorb/graphics/SpriteFont.java @@ -0,0 +1,315 @@ +package funorb.graphics; + +public final class SpriteFont extends Font { + private final byte[][] _H; + + public SpriteFont(final byte[] var1, final int[] xs, final int[] ys, final int[] widths, final int[] heights, final byte[][] pixels) { + super(var1, xs, ys, widths, heights); + this._H = pixels; + } + + public static void a183(final int[] var0, final byte[] var1, int var2, int var3, int var4, final int var5, final int var6, final int var7, final int var8, final int var9, int var10) { + var2 = ((var2 & 16711935) * var10 & -16711936) + ((var2 & '\uff00') * var10 & 16711680) >> 8; + var10 = 256 - var10; + + for (int var11 = -var7; var11 < 0; ++var11) { + for (int var12 = -var6; var12 < 0; ++var12) { + if (var1[var3] == 0) { + ++var4; + } else { + final int var13 = var0[var4]; + var0[var4++] = (((var13 & 16711935) * var10 & -16711936) + ((var13 & '\uff00') * var10 & 16711680) >> 8) + var2; + } + + var3 += var5; + } + + var4 += var8; + var3 += var9; + } + + } + + public static void a038(final int[] var0, final byte[] var1, final int var2, int var3, int var4, final int var5, int var6, final int var7, final int var8, final int var9) { + final int var10 = -(var6 >> 2); + var6 = -(var6 & 3); + + for (int var11 = -var7; var11 < 0; ++var11) { + int var12; + for (var12 = var10; var12 < 0; ++var12) { + if (var1[var3] == 0) { + ++var4; + } else { + var0[var4++] = var2; + } + + var3 += var5; + if (var1[var3] == 0) { + ++var4; + } else { + var0[var4++] = var2; + } + + var3 += var5; + if (var1[var3] == 0) { + ++var4; + } else { + var0[var4++] = var2; + } + + var3 += var5; + if (var1[var3] == 0) { + ++var4; + } else { + var0[var4++] = var2; + } + + var3 += var5; + } + + for (var12 = var6; var12 < 0; ++var12) { + if (var1[var3] == 0) { + ++var4; + } else { + var0[var4++] = var2; + } + + var3 += var5; + } + + var4 += var8; + var3 += var9; + } + + } + + public static void b038(final int[] var0, final byte[] var1, int var2, int var3, int var4, final int var5, final int var6, final int var7, final int var8, int var9) { + var2 = ((var2 & 16711935) * var9 & -16711936) + ((var2 & '\uff00') * var9 & 16711680) >> 8; + var9 = 256 - var9; + + for (int var10 = -var6; var10 < 0; ++var10) { + for (int var11 = -var5; var11 < 0; ++var11) { + if (var1[var3++] == 0) { + ++var4; + } else { + final int var12 = var0[var4]; + var0[var4++] = (((var12 & 16711935) * var9 & -16711936) + ((var12 & '\uff00') * var9 & 16711680) >> 8) + var2; + } + } + + var4 += var7; + var3 += var8; + } + + } + + public static void a111(final int[] var0, final byte[] var1, final int var2, int var3, int var4, int var5, final int var6, final int var7, final int var8) { + final int var9 = -(var5 >> 2); + var5 = -(var5 & 3); + + for (int var10 = -var6; var10 < 0; ++var10) { + int var11; + for (var11 = var9; var11 < 0; ++var11) { + if (var1[var3++] == 0) { + ++var4; + } else { + var0[var4++] = var2; + } + + if (var1[var3++] == 0) { + ++var4; + } else { + var0[var4++] = var2; + } + + if (var1[var3++] == 0) { + ++var4; + } else { + var0[var4++] = var2; + } + + if (var1[var3++] == 0) { + ++var4; + } else { + var0[var4++] = var2; + } + } + + for (var11 = var5; var11 < 0; ++var11) { + if (var1[var3++] == 0) { + ++var4; + } else { + var0[var4++] = var2; + } + } + + var4 += var7; + var3 += var8; + } + + } + + @Override + public void drawGlyph(final int index, int x, int y, int var4, int var5, final int color, final boolean var7) { + int var8 = Drawing.pixelIndex(x, y); + int var9 = Drawing.width - var4; + int var10 = 0; + int var11 = 0; + int var12; + if (y < Drawing.top) { + var12 = Drawing.top - y; + var5 -= var12; + y = Drawing.top; + var11 += var12 * var4; + var8 += var12 * Drawing.width; + } + + if (y + var5 > Drawing.bottom) { + var5 -= y + var5 - Drawing.bottom; + } + + if (x < Drawing.left) { + var12 = Drawing.left - x; + var4 -= var12; + x = Drawing.left; + var11 += var12; + var8 += var12; + var10 += var12; + var9 += var12; + } + + if (x + var4 > Drawing.right) { + var12 = x + var4 - Drawing.right; + var4 -= var12; + var10 += var12; + var9 += var12; + } + + if (var4 > 0 && var5 > 0) { + a111(Drawing.screenBuffer, this._H[index], color, var11, var8, var4, var5, var9, var10); + } + } + + @Override + public void drawGlyph(final int index, int x, int y, int var4, int var5, final int color, final int alpha, final boolean var8) { + int var9 = Drawing.pixelIndex(x, y); + int var10 = Drawing.width - var4; + int var11 = 0; + int var12 = 0; + int var13; + if (y < Drawing.top) { + var13 = Drawing.top - y; + var5 -= var13; + y = Drawing.top; + var12 += var13 * var4; + var9 += var13 * Drawing.width; + } + + if (y + var5 > Drawing.bottom) { + var5 -= y + var5 - Drawing.bottom; + } + + if (x < Drawing.left) { + var13 = Drawing.left - x; + var4 -= var13; + x = Drawing.left; + var12 += var13; + var9 += var13; + var11 += var13; + var10 += var13; + } + + if (x + var4 > Drawing.right) { + var13 = x + var4 - Drawing.right; + var4 -= var13; + var11 += var13; + var10 += var13; + } + + if (var4 > 0 && var5 > 0) { + b038(Drawing.screenBuffer, this._H[index], color, var12, var9, var4, var5, var10, var11, alpha); + } + } + + @Override + public void drawVerticalGlyph(final int index, int x, int y, int height, int width, final int color, final boolean var7) { + int var8 = Drawing.pixelIndex(x, y); + int var9 = Drawing.width - height; + final int var10 = width; + final byte var11 = -1; + int var12 = width - 1; + int var13; + if (y < Drawing.top) { + var13 = Drawing.top - y; + width -= var13; + y = Drawing.top; + var12 -= var13; + var8 += var13 * Drawing.width; + } + + if (y + width > Drawing.bottom) { + width -= y + width - Drawing.bottom; + } + + if (x < Drawing.left) { + var13 = Drawing.left - x; + height -= var13; + x = Drawing.left; + var12 += var13 * var10; + var8 += var13; + var9 += var13; + } + + if (x + height > Drawing.right) { + var13 = x + height - Drawing.right; + height -= var13; + var9 += var13; + } + + if (height > 0 && width > 0) { + final int var14 = var11 - var10 * height; + a038(Drawing.screenBuffer, this._H[index], color, var12, var8, var10, height, width, var9, var14); + } + } + + @Override + public void drawVerticalGlyph(final int index, int x, int y, int height, int width, final int color, final int alpha, final boolean var8) { + int var9 = Drawing.pixelIndex(x, y); + int var10 = Drawing.width - height; + final int var11 = width; + final byte var12 = -1; + int var13 = width - 1; + int var14; + if (y < Drawing.top) { + var14 = Drawing.top - y; + width -= var14; + y = Drawing.top; + var13 -= var14; + var9 += var14 * Drawing.width; + } + + if (y + width > Drawing.bottom) { + width -= y + width - Drawing.bottom; + } + + if (x < Drawing.left) { + var14 = Drawing.left - x; + height -= var14; + x = Drawing.left; + var13 += var14 * var11; + var9 += var14; + var10 += var14; + } + + if (x + height > Drawing.right) { + var14 = x + height - Drawing.right; + height -= var14; + var10 += var14; + } + + if (height > 0 && width > 0) { + final int var15 = var12 - var11 * height; + a183(Drawing.screenBuffer, this._H[index], color, var13, var9, var11, height, width, var10, var15, alpha); + } + } +} diff --git a/src/main/java/funorb/graphics/SpriteResource.java b/src/main/java/funorb/graphics/SpriteResource.java new file mode 100644 index 0000000..7a42ddf --- /dev/null +++ b/src/main/java/funorb/graphics/SpriteResource.java @@ -0,0 +1,189 @@ +package funorb.graphics; + +import funorb.cache.ResourceLoader; +import funorb.io.Buffer; + +import java.util.List; +import java.util.stream.IntStream; + +public final class SpriteResource { + public static Sprite loadSprite(final ResourceLoader loader, final String item) { + return loadSprite(loader, "", item); + } + + public static Sprite loadSprite(final ResourceLoader loader, final String group, final String item) { + return parseSprite(loader.getResource(group, item)); + } + + public static Sprite[] loadSprites(final ResourceLoader loader, final String group, final String item) { + return parseSprites(loader.getResource(group, item)); + } + + public static PalettedSymbol[] loadPalettedSprites(final ResourceLoader loader, final String group, final String item) { + return parsePalettedSprites(loader.getResource(group, item)); + } + + public static SpriteFont loadSpriteFont(final ResourceLoader spriteLoader, final ResourceLoader fontLoader, final String item) { + final byte[] spriteData = spriteLoader.getResource("lobby", item); + final byte[] fontData = fontLoader.getResource("lobby", item); + return parseSpriteFont(spriteData, fontData); + } + + public static PalettedSpriteFont loadPalettedSpriteFont(final ResourceLoader spriteLoader, final ResourceLoader fontLoader, final String group, final String item) { + final byte[] spriteData = spriteLoader.getResource(group, item); + final byte[] fontData = fontLoader.getResource(group, item); + return parsePalettedSpriteFont(spriteData, fontData); + } + + private static Sprite[] parseSprites(final byte[] data) { + return parseSpriteData(data, spriteConstructor).toArray(Sprite[]::new); + } + + private static Sprite parseSprite(final byte[] data) { + final List sprites = parseSpriteData(data, spriteConstructor); + assert sprites.size() == 1; + return sprites.get(0); + } + + private static PalettedSymbol[] parsePalettedSprites(final byte[] data) { + return parseSpriteData(data, palettedSpriteConstructor).toArray(PalettedSymbol[]::new); + } + + private static SpriteFont parseSpriteFont(final byte[] spriteData, final byte[] fontData) { + return parseSpriteData(spriteData, + (count, offsetX, offsetY, xs, ys, widths, heights, palette, pixels, alphas) -> + new SpriteFont(fontData, xs, ys, widths, heights, pixels)); + } + + private static PalettedSpriteFont parsePalettedSpriteFont(final byte[] spriteData, final byte[] fontData) { + return parseSpriteData(spriteData, + (count, offsetX, offsetY, xs, ys, widths, heights, palette, pixels, alphas) -> + new PalettedSpriteFont(fontData, xs, ys, widths, heights, palette, pixels)); + } + + private static List parseSpriteData(final byte[] data, final SingleConstructor ctor) { + return parseSpriteData(data, listConstructor(ctor)); + } + + private static T parseSpriteData(final byte[] data, final BulkConstructor ctor) { + final Buffer reader = new Buffer(data); + + reader.pos = data.length - 2; + final int sdImageCount = reader.readUShort(); + + reader.pos = data.length - 7 - (sdImageCount * 8); + final int sdOffsetX = reader.readUShort(); + final int sdOffsetY = reader.readUShort(); + final int paletteSize = reader.readUByte() + 1; + + final int[] sdXs = IntStream.range(0, sdImageCount).map(i -> reader.readUShort()).toArray(); + final int[] sdYs = IntStream.range(0, sdImageCount).map(i -> reader.readUShort()).toArray(); + final int[] sdWidths = IntStream.range(0, sdImageCount).map(i -> reader.readUShort()).toArray(); + final int[] sdHeights = IntStream.range(0, sdImageCount).map(i -> reader.readUShort()).toArray(); + + reader.pos = data.length - 7 - (3 * (paletteSize - 1)) - (sdImageCount * 8); + final int[] sdRgbPalette = new int[paletteSize]; + for (int i = 1; i < paletteSize; ++i) { + sdRgbPalette[i] = reader.readU24(); + if (sdRgbPalette[i] == 0) { + sdRgbPalette[i] = 1; + } + } + + final byte[][] sdAlphas = new byte[sdImageCount][]; + final byte[][] sdPixels = new byte[sdImageCount][]; + reader.pos = 0; + for (int i = 0; i < sdImageCount; ++i) { + final int width = sdWidths[i]; + final int height = sdHeights[i]; + final int var7 = height * width; + final byte[] pixels = sdPixels[i] = new byte[var7]; + final byte[] alphas = new byte[var7]; + boolean usesAlpha = false; + final int var11 = reader.readUByte(); + int var12; + if ((var11 & 1) == 0) { + for (var12 = 0; var7 > var12; ++var12) { + pixels[var12] = reader.readByte(); + } + + if ((var11 & 2) != 0) { + for (var12 = 0; var12 < var7; ++var12) { + final byte var13 = alphas[var12] = reader.readByte(); + usesAlpha |= var13 != -1; + } + } + } else { + var12 = 0; + + label90: + while (true) { + int var15; + if (width <= var12) { + if ((var11 & 2) == 0) { + break; + } + + var12 = 0; + + while (true) { + if (width <= var12) { + break label90; + } + + for (var15 = 0; height > var15; ++var15) { + final byte var14 = alphas[var12 + width * var15] = reader.readByte(); + usesAlpha |= var14 != -1; + } + + ++var12; + } + } + + for (var15 = 0; var15 < height; ++var15) { + pixels[var12 + width * var15] = reader.readByte(); + } + + ++var12; + } + } + + if (usesAlpha) { + sdAlphas[i] = alphas; + } + } + + return ctor.construct(sdImageCount, sdOffsetX, sdOffsetY, sdXs, sdYs, sdWidths, sdHeights, sdRgbPalette, sdPixels, sdAlphas); + } + + @FunctionalInterface + public interface SingleConstructor { + T construct(int offsetX, int offsetY, int x, int y, int width, int height, int[] palette, byte[] pixels, byte[] alphas); + } + + @FunctionalInterface + public interface BulkConstructor { + T construct(int count, int offsetX, int offsetY, int[] xs, int[] ys, int[] widths, int[] heights, int[] palette, byte[][] pixels, byte[][] alphas); + } + + private static final SingleConstructor spriteConstructor = (offsetX, offsetY, x, y, width, height, palette, pixels, alphas) -> { + final int pixelCount = height * width; + if (alphas == null) { + final int[] rgbs = IntStream.range(0, pixelCount).map(i -> palette[(int) pixels[i] & 255]).toArray(); + return new Sprite(offsetX, offsetY, x, y, width, height, rgbs); + } else { + final int[] rgbas = IntStream.range(0, pixelCount).map(i -> palette[(int) pixels[i] & 255] | ((alphas[i] & 0xff) << 24)).toArray(); + return new ArgbSprite(offsetX, offsetY, x, y, width, height, rgbas); + } + }; + + private static final SingleConstructor palettedSpriteConstructor = (offsetX, offsetY, x, y, width, height, palette, pixels, alphas) -> + new PalettedSymbol(offsetX, offsetY, x, y, width, height, pixels, palette); + + private static BulkConstructor> listConstructor(final SingleConstructor ctor) { + return (count, offsetX, offsetY, xs, ys, widths, heights, palette, pixels, alphas) -> + IntStream.range(0, count) + .mapToObj(i -> ctor.construct(offsetX, offsetY, xs[i], ys[i], widths[i], heights[i], palette, pixels[i], alphas[i])) + .toList(); + } +} diff --git a/src/main/java/funorb/graphics/Symbol.java b/src/main/java/funorb/graphics/Symbol.java new file mode 100644 index 0000000..90966a4 --- /dev/null +++ b/src/main/java/funorb/graphics/Symbol.java @@ -0,0 +1,14 @@ +package funorb.graphics; + +public abstract class Symbol { + public int x; + public int y; + public int height; + public int width; + public int advanceY; + public int advanceX; + + public abstract void draw(int x, int y); + + public abstract void draw(int x, int y, int alpha); +} diff --git a/src/main/java/funorb/graphics/mq_.java b/src/main/java/funorb/graphics/mq_.java new file mode 100644 index 0000000..35f7679 --- /dev/null +++ b/src/main/java/funorb/graphics/mq_.java @@ -0,0 +1,35 @@ +package funorb.graphics; + +public final class mq_ { + private static final int[] _bro = new int[]{0, 50, 101, 151, 201, 251, 302, 352, 402, 452, 503, 553, 603, 653, 704, 754, 804, 854, 905, 955, 1005, 1056, 1106, 1156, 1206, 1257, 1307, 1357, 1407, 1458, 1508, 1558, 1608, 1659, 1709, 1759, 1809, 1860, 1910, 1960, 2010, 2061, 2111, 2161, 2211, 2261, 2312, 2362, 2412, 2462, 2513, 2563, 2613, 2663, 2714, 2764, 2814, 2864, 2914, 2965, 3015, 3065, 3115, 3165, 3216, 3266, 3316, 3366, 3417, 3467, 3517, 3567, 3617, 3667, 3718, 3768, 3818, 3868, 3918, 3969, 4019, 4069, 4119, 4169, 4219, 4270, 4320, 4370, 4420, 4470, 4520, 4570, 4621, 4671, 4721, 4771, 4821, 4871, 4921, 4972, 5022, 5072, 5122, 5172, 5222, 5272, 5322, 5372, 5422, 5473, 5523, 5573, 5623, 5673, 5723, 5773, 5823, 5873, 5923, 5973, 6023, 6073, 6123, 6173, 6224, 6274, 6324, 6374, 6424, 6474, 6524, 6574, 6624, 6674, 6724, 6774, 6824, 6874, 6924, 6974, 7024, 7074, 7124, 7174, 7224, 7273, 7323, 7373, 7423, 7473, 7523, 7573, 7623, 7673, 7723, 7773, 7823, 7873, 7923, 7972, 8022, 8072, 8122, 8172, 8222, 8272, 8322, 8371, 8421, 8471, 8521, 8571, 8621, 8670, 8720, 8770, 8820, 8870, 8919, 8969, 9019, 9069, 9119, 9168, 9218, 9268, 9318, 9367, 9417, 9467, 9517, 9566, 9616, 9666, 9716, 9765, 9815, 9865, 9914, 9964, 10014, 10063, 10113, 10163, 10212, 10262, 10312, 10361, 10411, 10461, 10510, 10560, 10609, 10659, 10709, 10758, 10808, 10857, 10907, 10956, 11006, 11056, 11105, 11155, 11204, 11254, 11303, 11353, 11402, 11452, 11501, 11551, 11600, 11650, 11699, 11749, 11798, 11847, 11897, 11946, 11996, 12045, 12095, 12144, 12193, 12243, 12292, 12341, 12391, 12440, 12490, 12539, 12588, 12638, 12687, 12736, 12785, 12835, 12884, 12933, 12983, 13032, 13081, 13130, 13180, 13229, 13278, 13327, 13376, 13426, 13475, 13524, 13573, 13622, 13672, 13721, 13770, 13819, 13868, 13917, 13966, 14016, 14065, 14114, 14163, 14212, 14261, 14310, 14359, 14408, 14457, 14506, 14555, 14604, 14653, 14702, 14751, 14800, 14849, 14898, 14947, 14996, 15045, 15094, 15143, 15192, 15240, 15289, 15338, 15387, 15436, 15485, 15534, 15582, 15631, 15680, 15729, 15778, 15826, 15875, 15924, 15973, 16021, 16070, 16119, 16168, 16216, 16265, 16314, 16362, 16411, 16460, 16508, 16557, 16606, 16654, 16703, 16751, 16800, 16849, 16897, 16946, 16994, 17043, 17091, 17140, 17188, 17237, 17285, 17334, 17382, 17431, 17479, 17528, 17576, 17625, 17673, 17721, 17770, 17818, 17867, 17915, 17963, 18012, 18060, 18108, 18156, 18205, 18253, 18301, 18350, 18398, 18446, 18494, 18543, 18591, 18639, 18687, 18735, 18783, 18832, 18880, 18928, 18976, 19024, 19072, 19120, 19168, 19216, 19264, 19313, 19361, 19409, 19457, 19505, 19553, 19600, 19648, 19696, 19744, 19792, 19840, 19888, 19936, 19984, 20032, 20080, 20127, 20175, 20223, 20271, 20319, 20366, 20414, 20462, 20510, 20557, 20605, 20653, 20701, 20748, 20796, 20844, 20891, 20939, 20987, 21034, 21082, 21129, 21177, 21224, 21272, 21320, 21367, 21415, 21462, 21510, 21557, 21604, 21652, 21699, 21747, 21794, 21842, 21889, 21936, 21984, 22031, 22078, 22126, 22173, 22220, 22268, 22315, 22362, 22409, 22457, 22504, 22551, 22598, 22645, 22693, 22740, 22787, 22834, 22881, 22928, 22975, 23022, 23069, 23116, 23163, 23210, 23257, 23304, 23351, 23398, 23445, 23492, 23539, 23586, 23633, 23680, 23727, 23774, 23820, 23867, 23914, 23961, 24008, 24054, 24101, 24148, 24195, 24241, 24288, 24335, 24381, 24428, 24475, 24521, 24568, 24614, 24661, 24708, 24754, 24801, 24847, 24894, 24940, 24987, 25033, 25080, 25126, 25172, 25219, 25265, 25312, 25358, 25404, 25451, 25497, 25543, 25589, 25636, 25682, 25728, 25774, 25821, 25867, 25913, 25959, 26005, 26051, 26098, 26144, 26190, 26236, 26282, 26328, 26374, 26420, 26466, 26512, 26558, 26604, 26650, 26696, 26742, 26787, 26833, 26879, 26925, 26971, 27017, 27062, 27108, 27154, 27200, 27245, 27291, 27337, 27382, 27428, 27474, 27519, 27565, 27611, 27656, 27702, 27747, 27793, 27838, 27884, 27929, 27975, 28020, 28066, 28111, 28156, 28202, 28247, 28293, 28338, 28383, 28429, 28474, 28519, 28564, 28610, 28655, 28700, 28745, 28790, 28835, 28881, 28926, 28971, 29016, 29061, 29106, 29151, 29196, 29241, 29286, 29331, 29376, 29421, 29466, 29511, 29555, 29600, 29645, 29690, 29735, 29780, 29824, 29869, 29914, 29959, 30003, 30048, 30093, 30137, 30182, 30226, 30271, 30316, 30360, 30405, 30449, 30494, 30538, 30583, 30627, 30672, 30716, 30760, 30805, 30849, 30893, 30938, 30982, 31026, 31071, 31115, 31159, 31203, 31248, 31292, 31336, 31380, 31424, 31468, 31512, 31556, 31600, 31644, 31688, 31732, 31776, 31820, 31864, 31908, 31952, 31996, 32040, 32084, 32127, 32171, 32215, 32259, 32303, 32346, 32390, 32434, 32477, 32521, 32565, 32608, 32652, 32695, 32739, 32783, 32826, 32870, 32913, 32956, 33000, 33043, 33087, 33130, 33173, 33217, 33260, 33303, 33347, 33390, 33433, 33476, 33520, 33563, 33606, 33649, 33692, 33735, 33778, 33821, 33865, 33908, 33951, 33994, 34037, 34079, 34122, 34165, 34208, 34251, 34294, 34337, 34380, 34422, 34465, 34508, 34551, 34593, 34636, 34679, 34721, 34764, 34806, 34849, 34892, 34934, 34977, 35019, 35062, 35104, 35146, 35189, 35231, 35274, 35316, 35358, 35401, 35443, 35485, 35527, 35570, 35612, 35654, 35696, 35738, 35781, 35823, 35865, 35907, 35949, 35991, 36033, 36075, 36117, 36159, 36201, 36243, 36284, 36326, 36368, 36410, 36452, 36493, 36535, 36577, 36619, 36660, 36702, 36744, 36785, 36827, 36868, 36910, 36951, 36993, 37034, 37076, 37117, 37159, 37200, 37241, 37283, 37324, 37365, 37407, 37448, 37489, 37530, 37572, 37613, 37654, 37695, 37736, 37777, 37818, 37859, 37900, 37941, 37982, 38023, 38064, 38105, 38146, 38187, 38228, 38269, 38309, 38350, 38391, 38432, 38472, 38513, 38554, 38594, 38635, 38675, 38716, 38757, 38797, 38838, 38878, 38919, 38959, 38999, 39040, 39080, 39120, 39161, 39201, 39241, 39282, 39322, 39362, 39402, 39442, 39482, 39523, 39563, 39603, 39643, 39683, 39723, 39763, 39803, 39843, 39882, 39922, 39962, 40002, 40042, 40082, 40121, 40161, 40201, 40241, 40280, 40320, 40359, 40399, 40439, 40478, 40518, 40557, 40597, 40636, 40675, 40715, 40754, 40794, 40833, 40872, 40912, 40951, 40990, 41029, 41068, 41108, 41147, 41186, 41225, 41264, 41303, 41342, 41381, 41420, 41459, 41498, 41537, 41576, 41614, 41653, 41692, 41731, 41770, 41808, 41847, 41886, 41924, 41963, 42002, 42040, 42079, 42117, 42156, 42194, 42233, 42271, 42309, 42348, 42386, 42424, 42463, 42501, 42539, 42578, 42616, 42654, 42692, 42730, 42768, 42806, 42844, 42882, 42920, 42958, 42996, 43034, 43072, 43110, 43148, 43186, 43223, 43261, 43299, 43337, 43374, 43412, 43450, 43487, 43525, 43562, 43600, 43638, 43675, 43713, 43750, 43787, 43825, 43862, 43899, 43937, 43974, 44011, 44049, 44086, 44123, 44160, 44197, 44234, 44271, 44308, 44345, 44382, 44419, 44456, 44493, 44530, 44567, 44604, 44641, 44677, 44714, 44751, 44788, 44824, 44861, 44898, 44934, 44971, 45007, 45044, 45080, 45117, 45153, 45190, 45226, 45262, 45299, 45335, 45371, 45408, 45444, 45480, 45516, 45552, 45589, 45625, 45661, 45697, 45733, 45769, 45805, 45841, 45877, 45912, 45948, 45984, 46020, 46056, 46091, 46127, 46163, 46199, 46234, 46270, 46305, 46341, 46376, 46412, 46447, 46483, 46518, 46554, 46589, 46624, 46660, 46695, 46730, 46765, 46801, 46836, 46871, 46906, 46941, 46976, 47011, 47046, 47081, 47116, 47151, 47186, 47221, 47256, 47291, 47325, 47360, 47395, 47430, 47464, 47499, 47534, 47568, 47603, 47637, 47672, 47706, 47741, 47775, 47809, 47844, 47878, 47912, 47947, 47981, 48015, 48049, 48084, 48118, 48152, 48186, 48220, 48254, 48288, 48322, 48356, 48390, 48424, 48458, 48491, 48525, 48559, 48593, 48626, 48660, 48694, 48727, 48761, 48795, 48828, 48862, 48895, 48929, 48962, 48995, 49029, 49062, 49095, 49129, 49162, 49195, 49228, 49262, 49295, 49328, 49361, 49394, 49427, 49460, 49493, 49526, 49559, 49592, 49624, 49657, 49690, 49723, 49756, 49788, 49821, 49854, 49886, 49919, 49951, 49984, 50016, 50049, 50081, 50114, 50146, 50178, 50211, 50243, 50275, 50307, 50340, 50372, 50404, 50436, 50468, 50500, 50532, 50564, 50596, 50628, 50660, 50692, 50724, 50756, 50787, 50819, 50851, 50882, 50914, 50946, 50977, 51009, 51041, 51072, 51104, 51135, 51166, 51198, 51229, 51260, 51292, 51323, 51354, 51386, 51417, 51448, 51479, 51510, 51541, 51572, 51603, 51634, 51665, 51696, 51727, 51758, 51789, 51819, 51850, 51881, 51911, 51942, 51973, 52003, 52034, 52065, 52095, 52126, 52156, 52186, 52217, 52247, 52277, 52308, 52338, 52368, 52398, 52429, 52459, 52489, 52519, 52549, 52579, 52609, 52639, 52669, 52699, 52729, 52759, 52788, 52818, 52848, 52878, 52907, 52937, 52967, 52996, 53026, 53055, 53085, 53114, 53144, 53173, 53202, 53232, 53261, 53290, 53319, 53349, 53378, 53407, 53436, 53465, 53494, 53523, 53552, 53581, 53610, 53639, 53668, 53697, 53726, 53754, 53783, 53812, 53840, 53869, 53898, 53926, 53955, 53983, 54012, 54040, 54069, 54097, 54125, 54154, 54182, 54210, 54239, 54267, 54295, 54323, 54351, 54379, 54407, 54435, 54463, 54491, 54519, 54547, 54575, 54603, 54630, 54658, 54686, 54714, 54741, 54769, 54796, 54824, 54852, 54879, 54906, 54934, 54961, 54989, 55016, 55043, 55071, 55098, 55125, 55152, 55179, 55206, 55233, 55260, 55288, 55314, 55341, 55368, 55395, 55422, 55449, 55476, 55502, 55529, 55556, 55582, 55609, 55636, 55662, 55689, 55715, 55742, 55768, 55794, 55821, 55847, 55873, 55900, 55926, 55952, 55978, 56004, 56030, 56056, 56082, 56108, 56134, 56160, 56186, 56212, 56238, 56264, 56289, 56315, 56341, 56367, 56392, 56418, 56443, 56469, 56494, 56520, 56545, 56571, 56596, 56621, 56647, 56672, 56697, 56722, 56747, 56773, 56798, 56823, 56848, 56873, 56898, 56923, 56948, 56972, 56997, 57022, 57047, 57072, 57096, 57121, 57145, 57170, 57195, 57219, 57244, 57268, 57293, 57317, 57341, 57366, 57390, 57414, 57438, 57463, 57487, 57511, 57535, 57559, 57583, 57607, 57631, 57655, 57679, 57703, 57726, 57750, 57774, 57798, 57821, 57845, 57869, 57892, 57916, 57939, 57963, 57986, 58009, 58033, 58056, 58079, 58103, 58126, 58149, 58172, 58195, 58219, 58242, 58265, 58288, 58311, 58334, 58356, 58379, 58402, 58425, 58448, 58470, 58493, 58516, 58538, 58561, 58583, 58606, 58628, 58651, 58673, 58696, 58718, 58740, 58763, 58785, 58807, 58829, 58851, 58873, 58896, 58918, 58940, 58962, 58983, 59005, 59027, 59049, 59071, 59093, 59114, 59136, 59158, 59179, 59201, 59222, 59244, 59265, 59287, 59308, 59330, 59351, 59372, 59393, 59415, 59436, 59457, 59478, 59499, 59520, 59541, 59562, 59583, 59604, 59625, 59646, 59667, 59687, 59708, 59729, 59750, 59770, 59791, 59811, 59832, 59852, 59873, 59893, 59914, 59934, 59954, 59975, 59995, 60015, 60035, 60055, 60075, 60096, 60116, 60136, 60156, 60175, 60195, 60215, 60235, 60255, 60275, 60294, 60314, 60334, 60353, 60373, 60392, 60412, 60431, 60451, 60470, 60490, 60509, 60528, 60547, 60567, 60586, 60605, 60624, 60643, 60662, 60681, 60700, 60719, 60738, 60757, 60776, 60794, 60813, 60832, 60851, 60869, 60888, 60906, 60925, 60943, 60962, 60980, 60999, 61017, 61035, 61054, 61072, 61090, 61108, 61127, 61145, 61163, 61181, 61199, 61217, 61235, 61253, 61270, 61288, 61306, 61324, 61341, 61359, 61377, 61394, 61412, 61429, 61447, 61464, 61482, 61499, 61517, 61534, 61551, 61568, 61586, 61603, 61620, 61637, 61654, 61671, 61688, 61705, 61722, 61739, 61756, 61772, 61789, 61806, 61823, 61839, 61856, 61873, 61889, 61906, 61922, 61939, 61955, 61971, 61988, 62004, 62020, 62036, 62053, 62069, 62085, 62101, 62117, 62133, 62149, 62165, 62181, 62197, 62212, 62228, 62244, 62260, 62275, 62291, 62307, 62322, 62338, 62353, 62369, 62384, 62400, 62415, 62430, 62445, 62461, 62476, 62491, 62506, 62521, 62536, 62551, 62566, 62581, 62596, 62611, 62626, 62641, 62655, 62670, 62685, 62699, 62714, 62729, 62743, 62758, 62772, 62787, 62801, 62815, 62830, 62844, 62858, 62872, 62886, 62901, 62915, 62929, 62943, 62957, 62971, 62985, 62998, 63012, 63026, 63040, 63054, 63067, 63081, 63095, 63108, 63122, 63135, 63149, 63162, 63175, 63189, 63202, 63215, 63229, 63242, 63255, 63268, 63281, 63294, 63307, 63320, 63333, 63346, 63359, 63372, 63385, 63397, 63410, 63423, 63435, 63448, 63461, 63473, 63486, 63498, 63510, 63523, 63535, 63547, 63560, 63572, 63584, 63596, 63608, 63621, 63633, 63645, 63657, 63668, 63680, 63692, 63704, 63716, 63728, 63739, 63751, 63763, 63774, 63786, 63797, 63809, 63820, 63832, 63843, 63854, 63866, 63877, 63888, 63899, 63910, 63922, 63933, 63944, 63955, 63966, 63976, 63987, 63998, 64009, 64020, 64031, 64041, 64052, 64062, 64073, 64084, 64094, 64105, 64115, 64125, 64136, 64146, 64156, 64167, 64177, 64187, 64197, 64207, 64217, 64227, 64237, 64247, 64257, 64267, 64277, 64287, 64296, 64306, 64316, 64325, 64335, 64344, 64354, 64363, 64373, 64382, 64392, 64401, 64410, 64420, 64429, 64438, 64447, 64456, 64465, 64474, 64483, 64492, 64501, 64510, 64519, 64528, 64536, 64545, 64554, 64563, 64571, 64580, 64588, 64597, 64605, 64614, 64622, 64630, 64639, 64647, 64655, 64663, 64672, 64680, 64688, 64696, 64704, 64712, 64720, 64728, 64735, 64743, 64751, 64759, 64766, 64774, 64782, 64789, 64797, 64804, 64812, 64819, 64827, 64834, 64841, 64849, 64856, 64863, 64870, 64877, 64884, 64892, 64899, 64905, 64912, 64919, 64926, 64933, 64940, 64947, 64953, 64960, 64967, 64973, 64980, 64986, 64993, 64999, 65006, 65012, 65018, 65025, 65031, 65037, 65043, 65049, 65055, 65061, 65067, 65073, 65079, 65085, 65091, 65097, 65103, 65109, 65114, 65120, 65126, 65131, 65137, 65142, 65148, 65153, 65159, 65164, 65169, 65175, 65180, 65185, 65190, 65195, 65200, 65205, 65210, 65215, 65220, 65225, 65230, 65235, 65240, 65245, 65249, 65254, 65259, 65263, 65268, 65272, 65277, 65281, 65286, 65290, 65294, 65299, 65303, 65307, 65311, 65315, 65320, 65324, 65328, 65332, 65336, 65339, 65343, 65347, 65351, 65355, 65358, 65362, 65366, 65369, 65373, 65376, 65380, 65383, 65387, 65390, 65393, 65397, 65400, 65403, 65406, 65410, 65413, 65416, 65419, 65422, 65425, 65428, 65430, 65433, 65436, 65439, 65442, 65444, 65447, 65449, 65452, 65455, 65457, 65460, 65462, 65464, 65467, 65469, 65471, 65473, 65476, 65478, 65480, 65482, 65484, 65486, 65488, 65490, 65492, 65493, 65495, 65497, 65499, 65500, 65502, 65504, 65505, 65507, 65508, 65510, 65511, 65512, 65514, 65515, 65516, 65517, 65519, 65520, 65521, 65522, 65523, 65524, 65525, 65526, 65527, 65527, 65528, 65529, 65530, 65530, 65531, 65532, 65532, 65533, 65533, 65534, 65534, 65534, 65535, 65535, 65535, 65536, 65536, 65536, 65536, 65536, 65536}; + + public static int b080mq(final int n) { + final int n2 = n & 0x1fff; + if (n2 < 0x1000) { + return n2 < 0x800 ? _bro[0x800 - n2] : -_bro[n2 - 0x800]; + } else { + return n2 < 0x1800 ? -_bro[0x1800 - n2] : _bro[n2 - 0x1800]; + } + } + + public static int a353je(final int n) { + final int n2 = n & 0x1fff; + if (n2 >= 0x1000) { + return n2 < 0x1800 ? -_bro[n2 - 0x1000] : -_bro[0x2000 - n2]; + } else { + return n2 < 0x800 ? _bro[n2] : _bro[0x1000 - n2]; + } + } + + public static int[] a977mq(final int var0, final int var2) { + final int var3 = a353je(var0); + final int var4 = b080mq(var0); + final int var5 = a353je(var2); + final int var6 = b080mq(var2); + final int var7 = (int) ((long) var3 * (long) var5 >> 16); + final int var8 = (int) ((long) var3 * (long) var6 >> 16); + final int var9 = (int) ((long) var4 * (long) var5 >> 16); + final int var10 = (int) ((long) var6 * (long) var4 >> 16); + return new int[]{0, 0, 0, var6, 0, var5, var7, var4, -var8, -var9, var3, var10}; + } +} diff --git a/src/main/java/funorb/graphics/vector/RasterSpan.java b/src/main/java/funorb/graphics/vector/RasterSpan.java new file mode 100644 index 0000000..592cadc --- /dev/null +++ b/src/main/java/funorb/graphics/vector/RasterSpan.java @@ -0,0 +1,40 @@ +package funorb.graphics.vector; + +public final class RasterSpan { + private static RasterSpan pool; + + public RasterSpan next = null; + public int x; + public int width; + public int alpha1; + public int alpha2; + public int alphaStep; + + public static RasterSpan create(final RasterSpan next, final int x, final int width, final int alpha1, final int alpha2, final int alphaStep) { + RasterSpan span = pool; + if (span == null) { + span = new RasterSpan(); + } else { + pool = pool.next; + } + + span.next = next; + span.x = x; + span.width = width; + span.alpha1 = alpha1; + span.alpha2 = alpha2; + span.alphaStep = alphaStep; + if (span.width < 0) { + throw new RuntimeException(); + } else if (span.alpha2 == 0 && span.alphaStep == 0 && (span.alpha1 == 0 || span.width != 1)) { + throw new RuntimeException(); + } + + return span; + } + + public void release() { + this.next = pool; + pool = this; + } +} diff --git a/src/main/java/funorb/graphics/vector/VectorDrawing.java b/src/main/java/funorb/graphics/vector/VectorDrawing.java new file mode 100644 index 0000000..37b9738 --- /dev/null +++ b/src/main/java/funorb/graphics/vector/VectorDrawing.java @@ -0,0 +1,395 @@ +package funorb.graphics.vector; + +import funorb.graphics.Drawing; +import funorb.graphics.Point; +import funorb.util.MathUtil; + +import java.util.Arrays; + +public final class VectorDrawing { + private static RasterSpan[] spans; + private static RasterSpan nextSpan = null; + + private static int firstScanline; + private static int lastScanline; + private static int currentScanline; + + private VectorDrawing() {} + + public static void fillPolygon(final Point[] points, final int color) { + initializeFillPolygon(); + a450bk(points); + + nextSpan = null; + currentScanline = firstScanline; + + final int rb = color & 0xff00ff; + final int g = color & 0x00ff00; + while (true) { + RasterSpan span; + int n; + do { + if ((span = nextSpan()) == null) { + return; + } + n = (Drawing.width * currentScanline) + span.x; + } while (span.x >= Drawing.width); + + int i = span.width; + int var9 = span.alpha2; + if (span.x >= 0) { + int alpha = span.alpha1 & 511; + if (alpha > 256) { + alpha = 512 - alpha; + } + final int color2 = Drawing.screenBuffer[n]; + Drawing.screenBuffer[n++] = Drawing.alphaOver(rb, g, color2, alpha); + } else { + i += span.x + 1; + n -= span.x; + var9 += (span.x + 1) * span.alphaStep; + span.x = 0; + } + + i = Math.min(i, Math.min(1000, Drawing.width - span.x)); + for (--i; i > 0; --i) { + int alpha = var9 & 511; + if (alpha > 256) { + alpha = 512 - alpha; + } + final int color2 = Drawing.screenBuffer[n]; + Drawing.screenBuffer[n++] = Drawing.alphaOver(rb, g, color2, alpha); + var9 += span.alphaStep; + } + } + } + + private static void initializeFillPolygon() { + firstScanline = Drawing.height - 1; + lastScanline = 0; + if (spans != null && Drawing.height <= spans.length) { + Arrays.fill(spans, 0, Drawing.height, null); + } else { + spans = new RasterSpan[Drawing.height]; + } + } + + private static void a450bk(final Point[] points) { + for (final Point point : points) { + int y = point.y >> 4; + firstScanline = MathUtil.clamp(firstScanline, 0, y); + + ++y; + if (lastScanline < y) { + lastScanline = Drawing.height > y ? y : Drawing.height - 1; + } + } + + Point prev = points[points.length - 1]; + for (final Point point : points) { + if (point.y > prev.y) { + a170tc(prev, point, true); + } else if (prev.y > point.y) { + a170tc(point, prev, false); + } + prev = point; + } + } + + private static RasterSpan nextSpan() { + while (nextSpan == null && currentScanline < lastScanline) { + nextSpan = spans[currentScanline++]; + } + if (nextSpan == null) { + return null; + } + + RasterSpan var1 = nextSpan.next; + if (var1 != null) { + while (nextSpan.x == var1.x) { + final int var2 = nextSpan.width - var1.width; + if (var2 > 0) { + splitAfter(nextSpan, var1.width); + } else if (var2 < 0) { + throw new RuntimeException(); + } + + nextSpan.alpha2 += var1.alpha2; + nextSpan.alpha1 += var1.alpha1; + nextSpan.alphaStep += var1.alphaStep; + final RasterSpan var3 = var1; + nextSpan.next = var1 = var1.next; + var3.release(); + if (nextSpan.alpha2 == 0 && nextSpan.alphaStep == 0) { + if (var1 != null && nextSpan.x == var1.x) { + var1.alpha1 += nextSpan.alpha1; + nextSpan.release(); + nextSpan = var1; + var1 = var1.next; + } else { + nextSpan.width = 1; + } + } + + if (var1 == null) { + var1 = nextSpan; + nextSpan = null; + var1.release(); + return var1; + } + } + + if (var1.x - nextSpan.x < nextSpan.width) { + splitAfter(nextSpan, var1.x - nextSpan.x); + } + } + + final RasterSpan g = nextSpan; + nextSpan = g.next; + g.release(); + return g; + } + + private static void splitAfter(RasterSpan orig, final int width) { + if (width <= 0 || width >= orig.width) { + throw new RuntimeException(); + } + + final RasterSpan fresh = RasterSpan.create( + null, + orig.x + width, + orig.width == Integer.MAX_VALUE ? orig.width : orig.width - width, + orig.alpha2 + orig.alphaStep * (width - 1), + orig.alpha2 + orig.alphaStep * width, + orig.alphaStep); + + orig.width = width; + while (orig.next != null && (orig.next.x < fresh.x || orig.next.x == fresh.x && orig.next.width > fresh.width)) { + orig = orig.next; + } + + fresh.next = orig.next; + orig.next = fresh; + } + + private static void a370sq(final int x, final int y, int width, final int alpha1, final int alpha2, final int alphaStep) { + if (y >= 0 && y < Drawing.height && width != 0) { + if (alpha2 == 0 && alphaStep == 0) { + if (alpha1 == 0) { + return; + } + width = 1; + } + + RasterSpan var6 = spans[y]; + if (var6 != null && var6.x <= x && (x != var6.x || var6.width >= width)) { + while (var6.next != null && (x > var6.next.x || x == var6.next.x && width < var6.next.width)) { + var6 = var6.next; + } + var6.next = RasterSpan.create(var6.next, x, width, alpha1, alpha2, alphaStep); + } else { + spans[y] = RasterSpan.create(var6, x, width, alpha1, alpha2, alphaStep); + } + } + } + + private static void a170tc(final Point p1, final Point p2, final boolean reverse) { + final int dx = p2.x - p1.x; + final int dy = p2.y - p1.y; + final int y1 = p1.y >> 4; + final int y1a = p1.y & 15; + final int y2 = p2.y >> 4; + final int y2a = p2.y & 15; + final int x1 = p1.x >> 4; + final int x1a = p1.x & 15; + final int x2 = p2.x >> 4; + final int x2a = p2.x & 15; + if (y1 == y2) { + if (x1 == x2) { + int var19 = (y2a - y1a) * (x2a + x1a) >> 1; + int var20 = (y2a - y1a) << 4; + if (reverse) { + var19 = -var19; + var20 = -var20; + } + + a370sq(x1, y1, Integer.MAX_VALUE, var19, var20, 0); + } else if (dx < 0) { + int var19 = (16 - x2a) * (16 - x2a) * -dy / (dx * 2); + int var20 = (24 - x2a) * -dy / dx; + int var21 = 16 * -dy / dx; + int var22 = 16 * (y2a - y1a) - x1a * x1a * -dy / (dx * 2); + int var23 = (y2a - y1a) * 16; + if (reverse) { + var19 = -var19; + var20 = -var20; + var22 = -var22; + var21 = -var21; + var23 = -var23; + } + + a370sq(x2, y1, -x2 + x1, var19, var20, var21); + a370sq(x1, y1, Integer.MAX_VALUE, var22, var23, 0); + } else { + int var19 = (-x1a + 16) * (-x1a + 16) * dy / (dx * 2); + int var20 = (24 - x1a) * dy / dx; + int var21 = 16 * dy / dx; + int var22 = -(x2a * x2a * dy / (2 * dx)) + (y2a - y1a) * 16; + int var23 = (-y1a + y2a) * 16; + if (reverse) { + var21 = -var21; + var20 = -var20; + var22 = -var22; + var23 = -var23; + var19 = -var19; + } + + a370sq(x1, y1, x2 - x1, var19, var20, var21); + a370sq(x2, y1, Integer.MAX_VALUE, var22, var23, 0); + } + } else { + final int var19 = dx * (-y1a + 16) / dy + p1.x; + int var20 = var19 >> 4; + int var21 = 15 & var19; + if (var20 == x1) { + int var22 = (-y1a + 16) * (32 - x1a - var21) / 2; + int var23 = -(16 * y1a) + 256; + if (reverse) { + var23 = -var23; + var22 = -var22; + } + + a370sq(x1, y1, Integer.MAX_VALUE, var22, var23, 0); + } else if (dx < 0) { + int var22 = -dy * (-var21 + 16) * (-var21 + 16) / (dx * 2); + int var23 = (-var21 + 24) * 16 * -dy / dx; + int var24 = -dy * 256 / dx; + int var25 = 16 * (-y1a + 16) + x1a * x1a * dy / (dx * 2); + int var26 = -(y1a * 16) + 256; + if (reverse) { + var26 = -var26; + var22 = -var22; + var24 = -var24; + var23 = -var23; + var25 = -var25; + } + + a370sq(var20, y1, -var20 + x1, var22, var23, var24); + a370sq(x1, y1, Integer.MAX_VALUE, var25, var26, 0); + } else { + int var22 = dy * (-x1a + 16) * (16 - x1a) / (2 * dx); + int var23 = 16 * (-x1a + 24) * dy / dx; + int var24 = (-(16 * dy) + 256) / dx; + int var25 = 16 * (16 - y1a) - var21 * var21 * dy / (2 * dx); + int var26 = 256 - y1a * 16; + if (reverse) { + var22 = -var22; + var25 = -var25; + var24 = -var24; + var26 = -var26; + var23 = -var23; + } + + a370sq(x1, y1, var20 - x1, var22, var23, var24); + a370sq(var20, y1, Integer.MAX_VALUE, var25, var26, 0); + } + + for (int var22 = 1 + y1; y2 > var22; ++var22) { + final int var23 = p1.x + dx * (16 * (-y1 + var22) - (y1a - 16)) / dy; + final int var24 = var23 >> 4; + final int var25 = var23 & 15; + if (var24 == var20) { + int var26 = 8 * (-var21 + 32 - var25); + int var27 = 256; + if (reverse) { + var27 = -var27; + var26 = -var26; + } + + a370sq(var20, var22, Integer.MAX_VALUE, var26, var27, 0); + } else if (dx >= 0) { + int var26 = dy * (16 - var21) * (-var21 + 16) / (dx * 2); + int var27 = (-var21 + 24) * 16 * dy / dx; + int var28 = 256 * dy / dx; + int var29 = -(var25 * var25 * dy / (dx * 2)) + 256; + int var30 = 256; + if (reverse) { + var28 = -var28; + var30 = -var30; + var27 = -var27; + var26 = -var26; + var29 = -var29; + } + + a370sq(var20, var22, var24 - var20, var26, var27, var28); + a370sq(var24, var22, Integer.MAX_VALUE, var29, var30, 0); + } else { + int var26 = (-var25 + 16) * (-var25 + 16) * -dy / (dx * 2); + int var27 = -dy * (-(var25 * 16) + 384) / dx; + int var28 = 256 * -dy / dx; + int var29 = 256 - var21 * var21 * -dy / (dx * 2); + int var30 = 256; + if (reverse) { + var29 = -var29; + var27 = -var27; + var30 = -var30; + var26 = -var26; + var28 = -var28; + } + + a370sq(var24, var22, var20 - var24, var26, var27, var28); + a370sq(var20, var22, Integer.MAX_VALUE, var29, var30, 0); + } + + var21 = var25; + var20 = var24; + } + + final int var19a = p2.x - dx * y2a / dy; + final int var21a = 15 & var19a; + final int var20a = var19a >> 4; + if (x2 == var20a) { + int var22 = (32 - (x2a + var21a)) * y2a / 2; + int var23 = 16 * y2a; + if (reverse) { + var22 = -var22; + var23 = -var23; + } + + a370sq(x2, y2, Integer.MAX_VALUE, var22, var23, 0); + } else if (dx >= 0) { + int var22 = (-var21a + 16) * (16 - var21a) * dy / (dx * 2); + int var23 = dy * 16 * (-var21a + 24) / dx; + int var24 = dy * 256 / dx; + int var25 = 16 * y2a - dy * x2a * x2a / (2 * dx); + int var26 = y2a * 16; + if (reverse) { + var24 = -var24; + var23 = -var23; + var25 = -var25; + var22 = -var22; + var26 = -var26; + } + + a370sq(var20a, y2, x2 - var20a, var22, var23, var24); + a370sq(x2, y2, Integer.MAX_VALUE, var25, var26, 0); + } else { + int var22 = (-x2a + 16) * (-x2a + 16) * -dy / (dx * 2); + int var23 = 16 * (24 - x2a) * -dy / dx; + int var24 = -dy * 256 / dx; + int var25 = -(-dy * var21a * var21a / (dx * 2)) + 16 * y2a; + int var26 = y2a * 16; + if (reverse) { + var24 = -var24; + var25 = -var25; + var26 = -var26; + var22 = -var22; + var23 = -var23; + } + + a370sq(x2, y2, -x2 + var20a, var22, var23, var24); + a370sq(var20a, y2, Integer.MAX_VALUE, var25, var26, 0); + } + } + } +} diff --git a/src/main/java/funorb/io/Buffer.java b/src/main/java/funorb/io/Buffer.java new file mode 100644 index 0000000..5f540e4 --- /dev/null +++ b/src/main/java/funorb/io/Buffer.java @@ -0,0 +1,516 @@ +package funorb.io; + +import funorb.Strings; +import funorb.shatteredplans.client.JagexApplet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.stream.IntStream; +import java.util.zip.CRC32; + +public class Buffer implements ReadableBuffer, WritableBuffer { + private static final int XTEA_MAGIC = 0x9e3779b9; + private static final int XTEA_ROUNDS = 32; + private static final int XTEA_BLOCK_SIZE = 8; + public static BigInteger RSA_EXPONENT = new BigInteger("65537"); + private static final BigInteger RSA_MODULO = new BigInteger("6757747274818513864204534133465045479284128469717186816691454417744823753827902036844748836683348383638677747113757906301249837209713747402067689777172847"); + + private static final int[] _vgw = new int[256]; + private static Buffer rsaBuffer; + private static Buffer xteaBuffer; + static { + for (int var1 = 0; var1 < 256; ++var1) { + int var0 = var1; + + for (int var2 = 0; var2 < 8; ++var2) { + if ((var0 & 1) == 1) { + var0 = -306674912 ^ var0 >>> 1; + } else { + var0 >>>= 1; + } + } + + _vgw[var1] = var0; + } + } + + public byte[] data; + public int pos; + + public Buffer(final int size) { + this.data = new byte[size]; + this.pos = 0; + } + + public Buffer(final byte[] data) { + this.data = data; + this.pos = 0; + } + + private static int computeCrc(final byte[] data, final int startPos, final int endPos) { + int var3 = -1; + + for (int var4 = startPos; var4 < endPos; ++var4) { + var3 = var3 >>> 8 ^ _vgw[255 & (var3 ^ data[var4])]; + } + + return ~var3; + } + + public static int computeCrc(final byte[] data, final int len) { + return computeCrc(data, 0, len); + } + + private static int alignForXTEA(final int n) { + if ((n & 7) == 0) { + return n; + } + return n + (8 - (n & 7)); + } + + @Override + @SuppressWarnings("unused") + public int readerIndex() { + return this.pos; + } + + @Override + public final void skipBytes(final int len) { + this.pos += len; + } + + @Override + public final @NotNull String readNullBracketedString() { + final byte var2 = this.data[this.pos++]; + if (var2 == 0) { + return this.readNullTerminatedString(); + } else { + throw new IllegalStateException(""); + } + } + + @Override + public final void writeNullBracketedString(final String str) { + final int var3 = str.indexOf(0); + if (var3 >= 0) { + throw new IllegalArgumentException(""); + } else { + this.data[this.pos++] = 0; + this.pos += Strings.encode1252String(str, this.data, this.pos, str.length()); + this.data[this.pos++] = 0; + } + } + + public final void c093(final int var1) { + this.data[-var1 + this.pos - 4] = (byte) (var1 >> 24); + this.data[-3 + this.pos - var1] = (byte) (var1 >> 16); + this.data[-var1 + this.pos - 2] = (byte) (var1 >> 8); + this.data[this.pos + (-var1 - 1)] = (byte) var1; + } + + @Override + public final void writeByte(final int val) { + this.data[this.pos++] = (byte) val; + } + + private void zeroPad(final int len) { + while (this.pos < len) { + this.data[this.pos++] = 0; + } + } + + public final void writeDigest(final int startPos) { + this.writeInt(computeCrc(this.data, startPos, this.pos)); + } + + public final int d410() { + final int nextByte = this.data[this.pos] & 255; + if (nextByte < 128) { + return this.readUByte() - 64; + } else { + return this.readUShort() - 0xC000; + } + } + + public final int readVariableInt() { + int val = 0; + byte low = this.data[this.pos++]; + while ((low & 0x80) != 0) { + val = (val | (low & 0x7f)) << 7; + low = this.data[this.pos++]; + } + + return val | low; + } + + @Override + @SuppressWarnings("unused") + public final void writeVariableInt(final int val) { + if (val >= (1 << 21)) this.data[this.pos++] = (byte) ( (val >>> 21) | 0x80); + if (val >= (1 << 14)) this.data[this.pos++] = (byte) (((val >>> 14) & 0x7f) | 0x80); + if (val >= (1 << 7)) this.data[this.pos++] = (byte) (((val >>> 7) & 0x7f) | 0x80); + this.data[this.pos++] = (byte) (val & 0x7f); + } + + @Override + public final byte readByte() { + return this.data[this.pos++]; + } + + @Override + public final int readVariable8_16() { + final int nextByte = this.data[this.pos] & 255; + if ((nextByte & 0x80) == 0) { + return this.readUByte(); + } else { + return this.readUShort() - 0x8000; + } + } + + @Override + public final void writeInt(final int val) { + this.data[this.pos++] = (byte) (val >> 24); + this.data[this.pos++] = (byte) (val >> 16); + this.data[this.pos++] = (byte) (val >> 8); + this.data[this.pos++] = (byte) val; + } + + @Override + public final void readBytes(final byte[] dest, final int len) { + for (int i = 0; i < len; ++i) { + dest[i] = this.data[this.pos++]; + } + } + + @Override + public final int readUShort() { + this.pos += 2; + return (this.data[this.pos - 1] & 255) + + ((this.data[this.pos - 2] & 255) << 8); + } + + public final int readVariable16_32() { + if (this.data[this.pos] >= 0) { + return this.readUShort(); + } else { + return this.readInt() & Integer.MAX_VALUE; + } + } + + @Override + public final int readUByte() { + return this.data[this.pos++] & 255; + } + + @Override + public final void writeShort(final int val) { + this.data[this.pos++] = (byte) (val >> 8); + this.data[this.pos++] = (byte) val; + } + + @Override + public final void writeNullTerminatedString(final String str) { + final int var3 = str.indexOf(0); + if (var3 < 0) { + this.pos += Strings.encode1252String(str, this.data, this.pos, str.length()); + this.data[this.pos++] = (byte) 0; + } else { + throw new IllegalArgumentException(""); + } + } + + private void writeU56(final long val) { + this.data[this.pos++] = (byte) ((int) (val >> 48)); + this.data[this.pos++] = (byte) ((int) (val >> 40)); + this.data[this.pos++] = (byte) ((int) (val >> 32)); + this.data[this.pos++] = (byte) ((int) (val >> 24)); + this.data[this.pos++] = (byte) ((int) (val >> 16)); + this.data[this.pos++] = (byte) ((int) (val >> 8)); + this.data[this.pos++] = (byte) ((int) val); + } + + @SuppressWarnings("UnusedReturnValue") + public final long readU56() { + return ((long) (this.data[this.pos++] & 255) << 48) + + ((long) (this.data[this.pos++] & 255) << 40) + + ((long) (this.data[this.pos++] & 255) << 32) + + ((long) (this.data[this.pos++] & 255) << 24) + + ((long) (this.data[this.pos++] & 255) << 16) + + ((long) (this.data[this.pos++] & 255) << 8) + + (long) (this.data[this.pos++] & 255); + } + + @Override + public final void writeLong(final long val) { + this.data[this.pos++] = (byte) ((int) (val >> 56)); + this.data[this.pos++] = (byte) ((int) (val >> 48)); + this.data[this.pos++] = (byte) ((int) (val >> 40)); + this.data[this.pos++] = (byte) ((int) (val >> 32)); + this.data[this.pos++] = (byte) ((int) (val >> 24)); + this.data[this.pos++] = (byte) ((int) (val >> 16)); + this.data[this.pos++] = (byte) ((int) (val >> 8)); + this.data[this.pos++] = (byte) ((int) val); + } + + @Override + public final void writeBytes(final byte[] data, final int len) { + for (int i = 0; i < len; ++i) { + this.data[this.pos++] = data[i]; + } + } + + @Override + public final void writeBytes(final byte[] data) { + this.writeBytes(data, data.length); + } + + public final void writeBytes(final int... data) { + for (final int b : data) { + this.writeByte(b); + } + } + + @Override + public final @NotNull String readNullTerminatedString() { + final int startPos = this.pos; + + while (this.data[this.pos] != 0) { + this.pos++; + } + this.pos++; + + final int len = this.pos - startPos - 1; + return len == 0 ? "" : Strings.decode1252String(this.data, startPos, len); + } + + public final void writePasswordHash(final String var2) { + long var3 = 0L; + long var5 = 0L; + final int var7 = var2.length(); + + for (int var8 = 19; var8 >= 0; --var8) { + var3 *= 38L; + if (var7 > var8) { + final char var9 = var2.charAt(var8); + if (var9 >= 'A' && var9 <= 'Z') { + var3 += var9 - 63; + } else if (var9 >= 'a' && var9 <= 'z') { + var3 += var9 + 2 - 97; + } else if (var9 >= '0' && var9 <= '9') { + var3 += 28 + var9 - 48; + } else { + ++var3; + } + } + + if (var8 == 10) { + var5 = var3; + var3 = 0L; + } + } + + this.writeU56(var3); + this.writeU56(var5); + } + + public final void writeI40(final long val) { + this.data[this.pos++] = (byte) ((int) (val >> 32)); + this.data[this.pos++] = (byte) ((int) (val >> 24)); + this.data[this.pos++] = (byte) ((int) (val >> 16)); + this.data[this.pos++] = (byte) ((int) (val >> 8)); + this.data[this.pos++] = (byte) ((int) val); + } + + @Override + public final long readLong() { + final long hi = (long) this.readInt() & 0xffffffffL; + final long lo = (long) this.readInt() & 0xffffffffL; + return (hi << 32) + lo; + } + + public final @Nullable String readNullableNullTerminatedString() { + if (this.data[this.pos] == 0) { + ++this.pos; + return null; + } else { + return this.readNullTerminatedString(); + } + } + + public final void a556(final int var2) { + if ((var2 & -128) != 0) { + if ((var2 & -16384) != 0) { + if ((-2097152 & var2) != 0) { + if ((-268435456 & var2) != 0) { + this.writeByte(var2 >>> 28 | 128); + } + + this.writeByte(var2 >>> 21 | 128); + } + + this.writeByte((2107852 | var2) >>> 14); + } + + this.writeByte(var2 >>> 7 | 128); + } + + this.writeByte(127 & var2); + } + + @Override + public final int readInt() { + this.pos += 4; + return (this.data[this.pos - 1] & 255) + + ((this.data[this.pos - 2] & 255) << 8) + + ((this.data[this.pos - 3] & 255) << 16) + + ((this.data[this.pos - 4] & 255) << 24); + } + + private void encryptXTEA(final int[] key) { + assert this.pos % XTEA_BLOCK_SIZE == 0; + final int blocks = this.pos / XTEA_BLOCK_SIZE; + this.pos = 0; + + for (int i = 0; i < blocks; ++i) { + int value1 = this.readInt(); + int value2 = this.readInt(); + int sum = 0; + + for (int j = 0; j < XTEA_ROUNDS; j++) { + value1 += (value2 + ((value2 << 4) ^ (value2 >>> 5))) ^ (sum + key[sum & 3]); + sum += XTEA_MAGIC; + value2 += (value1 + ((value1 << 4) ^ (value1 >>> 5))) ^ (sum + key[(sum >>> 11) & 3]); + } + + this.pos -= XTEA_BLOCK_SIZE; + this.writeInt(value1); + this.writeInt(value2); + } + } + + private void decryptXTEA(final int[] key, final int len) { + assert len % XTEA_BLOCK_SIZE == 0; + final int blocks = len / XTEA_BLOCK_SIZE; + final int startPos = this.pos; + for (int i = 0; i < blocks; i++) { + int value1 = this.readInt(); + int value2 = this.readInt(); + + @SuppressWarnings("NumericOverflow") + int sum = XTEA_MAGIC * XTEA_ROUNDS; + for (int j = 0; j < XTEA_ROUNDS; j++) { + value2 -= (value1 + ((value1 << 4) ^ (value1 >>> 5))) ^ (sum + key[(sum >>> 11) & 3]); + sum -= XTEA_MAGIC; + value1 -= (value2 + ((value2 << 4) ^ (value2 >>> 5))) ^ (sum + key[sum & 3]); + } + + this.pos -= XTEA_BLOCK_SIZE; + this.writeInt(value1); + this.writeInt(value2); + } + this.pos = startPos; + } + + public final void encryptRSA() { + final int len = this.pos; + this.pos = 0; + final byte[] plaintext = new byte[len]; + this.readBytes(plaintext, len); + final byte[] encrypted = new BigInteger(plaintext).modPow(RSA_EXPONENT, RSA_MODULO).toByteArray(); + this.pos = 0; + this.writeShort(encrypted.length); + this.writeBytes(encrypted); + } + + @SuppressWarnings("SameParameterValue") + private Buffer decryptRSA(final BigInteger exponent) { + final int len = this.readUShort(); + final byte[] encrypted = new byte[len]; + this.readBytes(encrypted, len); + final byte[] plaintext = new BigInteger(encrypted).modPow(exponent, RSA_MODULO).toByteArray(); + return new Buffer(plaintext); + } + + public final void writeEncrypted(final byte[] plaintext, final int len) { + final int alignedLen = alignForXTEA(len); + final int[] key = new int[4]; + Arrays.setAll(key, i -> JagexApplet.secureRandom.nextInt()); + + if (xteaBuffer == null || xteaBuffer.data.length < alignedLen) { + xteaBuffer = new Buffer(alignedLen); + } + + xteaBuffer.pos = 0; + xteaBuffer.writeBytes(plaintext, len); + xteaBuffer.zeroPad(alignedLen); + xteaBuffer.encryptXTEA(key); + + if (rsaBuffer == null || rsaBuffer.data.length < 100) { + rsaBuffer = new Buffer(100); + } + + rsaBuffer.pos = 0; + rsaBuffer.writeByte(10); + Arrays.stream(key).forEach(rsaBuffer::writeInt); + + rsaBuffer.writeShort(len); + rsaBuffer.encryptRSA(); + this.writeBytes(rsaBuffer.data, rsaBuffer.pos); + this.writeBytes(xteaBuffer.data, xteaBuffer.pos); + } + + @SuppressWarnings("SameParameterValue") + public final void decrypt(final BigInteger exponent, final int len) { + final Buffer keyBuffer = this.decryptRSA(exponent); + final int keyLen = keyBuffer.readUByte(); + assert keyLen == 10; + final int[] key = IntStream.range(0, 4).map(i -> keyBuffer.readInt()).toArray(); + this.decryptXTEA(key, len - this.pos); + } + + public final boolean f427() { + this.pos -= 4; + final int var2 = computeCrc(this.data, 0, this.pos); + + final int var3 = this.readInt(); + return var2 == var3; + } + + public final void insertLengthByte(final int len) { + this.data[this.pos - len - 1] = (byte) len; + } + + public final void withLengthByte(final Runnable action) { + final int startPos = ++this.pos; + action.run(); + this.insertLengthByte(this.pos - startPos); + } + + private void insertLengthShort(final int len) { + this.data[this.pos - len - 2] = (byte) (len >> 8); + this.data[this.pos - len - 1] = (byte) len; + } + + public final void withLengthShort(final Runnable action) { + this.pos += 2; + final int startPos = this.pos; + action.run(); + this.insertLengthShort(this.pos - startPos); + } + + public final void writeI24(@SuppressWarnings("SameParameterValue") final int val) { + this.data[this.pos++] = (byte) (val >> 16); + this.data[this.pos++] = (byte) (val >> 8); + this.data[this.pos++] = (byte) val; + } + + @Override + @SuppressWarnings("unused") + public final void writeCRC(final int len) { + final CRC32 crc = new CRC32(); + crc.update(this.data, this.pos - len, len); + this.writeInt((int) crc.getValue()); + } +} diff --git a/src/main/java/funorb/io/ByteContainer.java b/src/main/java/funorb/io/ByteContainer.java new file mode 100644 index 0000000..654836b --- /dev/null +++ b/src/main/java/funorb/io/ByteContainer.java @@ -0,0 +1,5 @@ +package funorb.io; + +public abstract class ByteContainer { + public abstract byte[] toByteArray(); +} diff --git a/src/main/java/funorb/io/Bzip2.java b/src/main/java/funorb/io/Bzip2.java new file mode 100644 index 0000000..7e8b5b7 --- /dev/null +++ b/src/main/java/funorb/io/Bzip2.java @@ -0,0 +1,448 @@ +package funorb.io; + +import java.util.Arrays; + +public final class Bzip2 { + private static final int ALL_DONE = 23; + private static final int SOME_LENGTH = 23; + private static final int SOME_CONSTANT = 50; + + private static final int[] _kpk = new int[100_000]; + private static final byte[][] huffmanCodes = new byte[6][258]; + private static final boolean[] huffmanCodesUsedMap = new boolean[256]; + private static final byte[] huffmanSelectors = new byte[18002]; + private static final int[][] _y = new int[6][258]; + private static final int[] _q = new int[256]; + private static final int[] _i = new int[6]; + private static final int[][] _o = new int[6][258]; + private static final boolean[] huffmanBlocksUsedMap = new boolean[16]; + private static final byte[] _D = new byte[4096]; + private static final byte[] huffmanCodeIndexes = new byte[256]; + private static final int[][] _H = new int[6][258]; + private static final byte[] huffmanGroupIndexes = new byte[18002]; + private static final int[] _l = new int[257]; + private static final int[] _K = new int[16]; + private static int _x; + private static int len; + private static byte _v; + private static int nextValueBits; + private static int _f; + private static int _G; + private static int _w; + private static int srcPos = 0; + private static byte[] src; + private static int _k; + private static byte[] dest; + private static int nextValue; + private static int _d = 0; + + private Bzip2() {} + + public static synchronized void decompress(final byte[] src, final byte[] dest) { + Bzip2.src = src; + Bzip2.dest = dest; + len = dest.length; + srcPos = 9; + _d = 0; + nextValueBits = 0; + nextValue = 0; + go(); + Bzip2.src = null; + Bzip2.dest = null; + } + + private static void a701(final byte[] huffmanCodes, final int codeCount, final int codeMin, final int codeMax, final int[] arr1, final int[] arr2, final int[] arr3) { + int var7 = 0; + for (int i = codeMin; i <= codeMax; ++i) { + for (int j = 0; j < codeCount; ++j) { + if (huffmanCodes[j] == i) { + arr3[var7] = j; + ++var7; + } + } + } + + Arrays.fill(arr1, 0, SOME_LENGTH, 0); + for (int i = 0; i < codeCount; ++i) { + ++arr1[huffmanCodes[i] + 1]; + } + for (int i = 1; i < SOME_LENGTH; ++i) { + arr1[i] += arr1[i - 1]; + } + + + Arrays.fill(arr2, 0, SOME_LENGTH, 0); + int var10 = 0; + for (int i = codeMin; i <= codeMax; ++i) { + var10 += arr1[i + 1] - arr1[i]; + arr2[i] = var10 - 1; + var10 <<= 1; + } + for (int i = codeMin + 1; i <= codeMax; ++i) { + arr1[i] = ((arr2[i - 1] + 1) << 1) - arr1[i]; + } + } + + + private static void go() { + do { + if (readByte() == ALL_DONE) { + return; + } + + skipBytes(9); + readBit(); + + final int origOffset = readBits(24); + for (int i = 0; i < 16; ++i) { + huffmanBlocksUsedMap[i] = readBool(); + } + + Arrays.fill(huffmanCodesUsedMap, false); + for (int i = 0; i < 16; ++i) { + if (huffmanBlocksUsedMap[i]) { + for (int j = 0; j < 16; ++j) { + if (readBool()) { + huffmanCodesUsedMap[i * 16 + j] = true; + } + } + } + } + + int huffmanCodeIndexesIndex = 0; + for (int i = 0; i < 256; ++i) { + if (huffmanCodesUsedMap[i]) { + huffmanCodeIndexes[huffmanCodeIndexesIndex] = (byte) i; + ++huffmanCodeIndexesIndex; + } + } + final int huffmanCodeCount = huffmanCodeIndexesIndex + 2; + + final int huffmanGroupCount = readBits(3); + final int huffmanSelectorCount = readBits(15); + for (int i = 0; i < huffmanSelectorCount; ++i) { + huffmanSelectors[i] = (byte) readUnary(); + } + + final byte[] huffmanGroupStack = new byte[6]; + for (byte i = 0; i < huffmanGroupCount; i++) { + huffmanGroupStack[i] = i; + } + for (int i = 0; i < huffmanSelectorCount; ++i) { + final byte selector = huffmanSelectors[i]; + final byte groupIndex = huffmanGroupStack[selector]; + for (byte j = selector; j > 0; --j) { + huffmanGroupStack[j] = huffmanGroupStack[j - 1]; + } + huffmanGroupStack[0] = groupIndex; + huffmanGroupIndexes[i] = groupIndex; + } + + for (int i = 0; i < huffmanGroupCount; ++i) { + int code = readBits(5); + for (int j = 0; j < huffmanCodeCount; ++j) { + while (readBool()) { + if (readBool()) { + --code; + } else { + ++code; + } + } + huffmanCodes[i][j] = (byte) code; + } + } + + for (int i = 0; i < huffmanGroupCount; ++i) { + byte codeMin = 32; + byte codeMax = 0; + + for (int j = 0; j < huffmanCodeCount; ++j) { + if (codeMax < huffmanCodes[i][j]) { + codeMax = huffmanCodes[i][j]; + } + if (codeMin > huffmanCodes[i][j]) { + codeMin = huffmanCodes[i][j]; + } + } + + a701(huffmanCodes[i], huffmanCodeCount, codeMin, codeMax, _y[i], _o[i], _H[i]); + _i[i] = codeMin; + } + + Arrays.fill(_q, 0); + + { + int var56 = _D.length - 1; + for (int i = 15; i >= 0; --i) { + for (int j = 15; j >= 0; --j) { + _D[var56] = (byte) (i * 16 + j); + --var56; + } + _K[i] = var56 + 1; + } + } + + int var46 = 0; + int var42 = 0; + byte var53 = huffmanGroupIndexes[0]; + int var22 = _i[var53]; + int[] var23 = _o[var53]; + int[] var25 = _H[var53]; + int[] var24 = _y[var53]; + + int var45 = common1(var22, var23, var25, var24); + int var44 = SOME_CONSTANT - 1; + while (var45 != huffmanCodeCount - 1) { + if (var45 == 0 || var45 == 1) { + int var47 = -1; + int var48 = 1; + + do { + if (var45 == 0) { + var47 += var48; + } else { + var47 += 2 * var48; + } + + var48 *= 2; + if (var44 == 0) { + ++var42; + var44 = SOME_CONSTANT; + var53 = huffmanGroupIndexes[var42]; + var22 = _i[var53]; + var23 = _o[var53]; + var25 = _H[var53]; + var24 = _y[var53]; + } + + --var44; + var45 = common1(var22, var23, var25, var24); + } while (var45 == 0 || var45 == 1); + ++var47; + final byte b1 = huffmanCodeIndexes[_D[_K[0]] & 255]; + for (_q[b1 & 255] += var47; var47 > 0; --var47) { + _kpk[var46] = b1 & 255; + ++var46; + } + } else { + int var33 = var45 - 1; + final byte b1; + if (var33 < 16) { + final int var30 = _K[0]; + b1 = _D[var30 + var33]; + for (; var33 > 3; var33 -= 4) { + final int var34 = var30 + var33; + _D[var34] = _D[var34 - 1]; + _D[var34 - 1] = _D[var34 - 2]; + _D[var34 - 2] = _D[var34 - 3]; + _D[var34 - 3] = _D[var34 - 4]; + } + while (var33 > 0) { + _D[var30 + var33] = _D[var30 + var33 - 1]; + --var33; + } + _D[var30] = b1; + } else { + int var31 = var33 / 16; + final int var32 = var33 % 16; + int var30 = _K[var31] + var32; + b1 = _D[var30]; + for (; var30 > _K[var31]; --var30) { + _D[var30] = _D[var30 - 1]; + } + + _K[var31]++; + for (; var31 > 0; --var31) { + _K[var31]--; + _D[_K[var31]] = _D[_K[var31 - 1] + 16 - 1]; + } + + _K[0]--; + _D[_K[0]] = b1; + if (_K[0] == 0) { + int var56 = _D.length - 1; + for (int i = 15; i >= 0; --i) { + for (int j = 15; j >= 0; --j) { + _D[var56] = _D[_K[i] + j]; + --var56; + } + _K[i] = var56 + 1; + } + } + } + + _q[huffmanCodeIndexes[b1 & 255] & 255]++; + _kpk[var46] = huffmanCodeIndexes[b1 & 255] & 255; + ++var46; + if (var44 == 0) { + ++var42; + var44 = 50; + var53 = huffmanGroupIndexes[var42]; + var22 = _i[var53]; + var23 = _o[var53]; + var25 = _H[var53]; + var24 = _y[var53]; + } + + --var44; + var45 = common1(var22, var23, var25, var24); + } + } + + _k = 0; + _v = 0; + _l[0] = 0; + + System.arraycopy(_q, 0, _l, 1, _q.length); + + for (int i = 1; i <= 256; ++i) { + _l[i] += _l[i - 1]; + } + for (int i = 0; i < var46; ++i) { + final int b1 = _kpk[i] & 255; + _kpk[_l[b1 & 255]] |= i << 8; + _l[b1 & 255]++; + } + + _w = _kpk[origOffset] >> 8; + _G = 0; + _w = _kpk[_w]; + _x = (byte) (_w & 255); + _w >>= 8; + ++_G; + _f = var46; + b855(); + } while (_G == _f + 1 && _k == 0); + } + + private static int common1(final int bits, final int[] var23, final int[] var25, final int[] var24) { + int var50 = bits; + int var51 = readBits(bits); + while (var51 > var23[var50]) { + ++var50; + var51 = (var51 << 1) | readBit(); + } + return var25[var51 - var24[var50]]; + } + + private static void b855() { + final int var12 = _f + 1; + + outer: + while (true) { + if (_k > 0) { + while (true) { + if (len == 0) { + return; + } + + if (_k == 1) { + dest[_d] = _v; + ++_d; + --len; + break; + } + + dest[_d] = _v; + --_k; + ++_d; + --len; + } + } + + while (_G != var12) { + _v = (byte) _x; + _w = _kpk[_w]; + final byte var1 = (byte) _w; + _w >>= 8; + ++_G; + if (var1 == _x) { + if (_G != var12) { + _k = 2; + _w = _kpk[_w]; + final byte b = (byte) _w; + _w >>= 8; + ++_G; + if (_G != var12) { + if (b == _x) { + _k = 3; + _w = _kpk[_w]; + final byte var71 = (byte) _w; + _w >>= 8; + ++_G; + if (_G != var12) { + if (var71 == _x) { + _w = _kpk[_w]; + final byte var72 = (byte) _w; + _w >>= 8; + ++_G; + _k = (var72 & 255) + 4; + _w = _kpk[_w]; + _x = (byte) _w; + _w >>= 8; + ++_G; + } else { + _x = var71; + } + } + } else { + _x = b; + } + } + continue outer; + } + + } else { + _x = var1; + } + if (len == 0) { + _k = 1; + return; + } + dest[_d] = _v; + ++_d; + --len; + } + + _k = 0; + break; + } + } + + private static int readBits(final int bits) { + while (nextValueBits < bits) { + nextValue = (nextValue << 8) | (src[srcPos] & 255); + nextValueBits += 8; + ++srcPos; + } + + final int leftoverBits = nextValueBits - bits; + nextValueBits = leftoverBits; + return (nextValue >> leftoverBits) & ((1 << bits) - 1); + } + + private static byte readBit() { + return (byte) readBits(1); + } + + private static boolean readBool() { + return readBit() == 1; + } + + private static byte readByte() { + return (byte) readBits(8); + } + + @SuppressWarnings("SameParameterValue") + private static void skipBytes(final int count) { + for (int i = 0; i < count; i++) { + readByte(); + } + } + + private static int readUnary() { + int val = 0; + while (readBool()) val++; + return val; + } +} diff --git a/src/main/java/funorb/io/CipheredBuffer.java b/src/main/java/funorb/io/CipheredBuffer.java new file mode 100644 index 0000000..364dd3c --- /dev/null +++ b/src/main/java/funorb/io/CipheredBuffer.java @@ -0,0 +1,64 @@ +package funorb.io; + +import funorb.util.IsaacCipher; +import org.jetbrains.annotations.Range; + +public final class CipheredBuffer extends Buffer { + private static final int[] _rqj = new int[]{0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, Integer.MAX_VALUE, -1}; + private IsaacCipher isaac; + private int _n; + + public CipheredBuffer(final byte[] data) { + super(data); + } + + public CipheredBuffer() { + super(5000); + } + + public void setCipher(final IsaacCipher isaac) { + this.isaac = isaac; + } + + public int b543(int var2) { + int var3 = this._n >> 3; + + int var4 = -(7 & this._n) + 8; + int var5 = 0; + + for (this._n += var2; var4 < var2; var4 = 8) { + var5 += (this.data[var3++] & _rqj[var4]) << -var4 + var2; + var2 -= var4; + } + + if (var4 == var2) { + var5 += _rqj[var4] & this.data[var3]; + } else { + var5 += this.data[var3] >> var4 - var2 & _rqj[var2]; + } + + return var5; + } + + public void writeCipheredByte(final int val) { + this.data[this.pos++] = (byte) (val + this.isaac.nextInt()); + } + + public void readCipheredBytes(final byte[] buffer, final int len) { + for (int i = 0; i < len; ++i) { + buffer[i] = (byte) (this.data[this.pos++] - this.isaac.nextInt()); + } + } + + public @Range(from=0, to=0xff) int readCipheredByte() { + return (this.data[this.pos++] - this.isaac.nextInt()) & 0xff; + } + + public void m150() { + this._n = this.pos * 8; + } + + public void i423() { + this.pos = (7 + this._n) / 8; + } +} diff --git a/src/main/java/funorb/io/DirectByteContainer.java b/src/main/java/funorb/io/DirectByteContainer.java new file mode 100644 index 0000000..9bcd429 --- /dev/null +++ b/src/main/java/funorb/io/DirectByteContainer.java @@ -0,0 +1,21 @@ +package funorb.io; + +import java.nio.ByteBuffer; + +public final class DirectByteContainer extends ByteContainer { + private ByteBuffer data; + + public void put(final byte[] bs) { + this.data = ByteBuffer.allocateDirect(bs.length); + this.data.position(0); + this.data.put(bs); + } + + @Override + public byte[] toByteArray() { + final byte[] bs = new byte[this.data.capacity()]; + this.data.position(0); + this.data.get(bs); + return bs; + } +} diff --git a/src/main/java/funorb/io/DuplexStream.java b/src/main/java/funorb/io/DuplexStream.java new file mode 100644 index 0000000..72d1a30 --- /dev/null +++ b/src/main/java/funorb/io/DuplexStream.java @@ -0,0 +1,196 @@ +package funorb.io; + +import funorb.shatteredplans.client.JagexApplet; +import funorb.shatteredplans.client.MailboxMessage; +import funorb.shatteredplans.client.MessagePumpThread; +import org.jetbrains.annotations.Range; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; + +public final class DuplexStream implements Runnable { + private final MessagePumpThread messagePumpThread; + private final Socket socket; + private final int bufferSize; + private final OutputStream outputStream; + private final InputStream inputStream; + private int readPos; + private MailboxMessage threadMessage; + private boolean ioExceptionOccurred; + private int writePos; + private byte[] buffer; + private boolean shutdownRequested; + + public DuplexStream(final Socket socket, final MessagePumpThread messagePumpThread) throws IOException { + this.readPos = 0; + this.writePos = 0; + this.ioExceptionOccurred = false; + this.shutdownRequested = false; + this.messagePumpThread = messagePumpThread; + this.socket = socket; + this.socket.setSoTimeout(JagexApplet.DEBUG_MODE ? 0 : 30000); + this.socket.setTcpNoDelay(true); + this.inputStream = this.socket.getInputStream(); + this.outputStream = this.socket.getOutputStream(); + this.bufferSize = 5000; + } + + public void write(final byte[] data, final int len) throws IOException { + if (!this.shutdownRequested) { + if (this.ioExceptionOccurred) { + this.ioExceptionOccurred = false; + throw new IOException(); + } else { + if (this.buffer == null) { + this.buffer = new byte[this.bufferSize]; + } + + synchronized (this) { + for (int i = 0; i < len; ++i) { + this.buffer[this.writePos] = data[i]; + this.writePos = (this.writePos + 1) % this.bufferSize; + if (this.writePos == (this.bufferSize - 100 + this.readPos) % this.bufferSize) { + throw new IOException(); + } + } + + if (this.threadMessage == null) { + this.threadMessage = this.messagePumpThread.sendSpawnThreadMessage(this, 3); + } + + this.notifyAll(); + } + } + } + } + + public void close() { + if (!this.shutdownRequested) { + synchronized (this) { + this.shutdownRequested = true; + this.notifyAll(); + } + + if (this.threadMessage != null) { + if (this.threadMessage.busyAwait() == MailboxMessage.Status.SUCCESS) { + try { + ((Thread) this.threadMessage.response).join(); + } catch (final InterruptedException e) {} + } + } + + this.threadMessage = null; + } + } + + public int readByte() throws IOException { + if (this.shutdownRequested) { + return 0; + } else { + return this.inputStream.read(); + } + } + + public void pollForException() throws IOException { + if (!this.shutdownRequested) { + if (this.ioExceptionOccurred) { + this.ioExceptionOccurred = false; + throw new IOException(); + } + } + } + + @Override + protected void finalize() { + this.close(); + } + + @Range(from = 0, to = Integer.MAX_VALUE) + public int inputAvailable() throws IOException { + if (this.shutdownRequested) { + return 0; + } else { + return this.inputStream.available(); + } + } + + @Override + public void run() { + while (true) { + final int len; + final int pos; + synchronized (this) { + if (this.writePos == this.readPos) { + if (this.shutdownRequested) { + break; + } + + try { + this.wait(); + } catch (final InterruptedException var8) { + } + } + + if (this.readPos <= this.writePos) { + len = this.writePos - this.readPos; + } else { + len = this.bufferSize - this.readPos; + } + + pos = this.readPos; + } + + if (len > 0) { + try { + this.outputStream.write(this.buffer, pos, len); + } catch (final IOException var7) { + this.ioExceptionOccurred = true; + } + + this.readPos = (len + this.readPos) % this.bufferSize; + + try { + if (this.writePos == this.readPos) { + this.outputStream.flush(); + } + } catch (final IOException var6) { + this.ioExceptionOccurred = true; + } + } + } + + try { + if (this.inputStream != null) { + this.inputStream.close(); + } + + if (this.outputStream != null) { + this.outputStream.close(); + } + + if (this.socket != null) { + this.socket.close(); + } + } catch (final IOException var9) { + } + + this.buffer = null; + } + + public void read(final byte[] out, int offset, int len) throws IOException { + if (!this.shutdownRequested) { + while (len > 0) { + final int bytesRead = this.inputStream.read(out, offset, len); + if (bytesRead <= 0) { + throw new EOFException(); + } + + offset += bytesRead; + len -= bytesRead; + } + } + } +} diff --git a/src/main/java/funorb/io/HuffmanCoder.java b/src/main/java/funorb/io/HuffmanCoder.java new file mode 100644 index 0000000..670e7ac --- /dev/null +++ b/src/main/java/funorb/io/HuffmanCoder.java @@ -0,0 +1,305 @@ +package funorb.io; + +import funorb.Strings; +import funorb.cache.ResourceLoader; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +public final class HuffmanCoder { + public static HuffmanCoder instance; + private final byte[] codes; + private final int[] _a; + private int[] _g; + + public static void initialize(final ResourceLoader loader) { + assert instance == null; + instance = new HuffmanCoder(Objects.requireNonNull(loader.getResource("", "huffman"))); + } + + private HuffmanCoder(final byte[] codes) { + this.codes = codes; + this._a = new int[codes.length]; + this._g = new int[8]; + final int[] var3 = new int[33]; + int var4 = 0; + + for (int i = 0; i < codes.length; ++i) { + final byte var6 = codes[i]; + if (var6 != 0) { + final int var7 = 1 << (32 - var6); + final int var8 = var3[var6]; + this._a[i] = var8; + + final int var9; + if ((var8 & var7) == 0) { + var9 = var8 | var7; + + for (int j = var6 - 1; j >= 1; --j) { + final int var11 = var3[j]; + if (var8 != var11) { + break; + } + + final int var12 = 1 << (32 - j); + if ((var11 & var12) != 0) { + var3[j] = var3[j - 1]; + break; + } + + var3[j] = var12 | var11; + } + } else { + var9 = var3[var6 - 1]; + } + var3[var6] = var9; + + for (int j = var6 + 1; j <= 32; ++j) { + if (var8 == var3[j]) { + var3[j] = var9; + } + } + + int var10 = 0; + for (int j = 0; j < var6; ++j) { + final int var12 = Integer.MIN_VALUE >>> j; + if ((var12 & var8) == 0) { + ++var10; + } else { + if (this._g[var10] == 0) { + this._g[var10] = var4; + } + + var10 = this._g[var10]; + } + + if (var10 >= this._g.length) { + final int[] var13 = new int[this._g.length * 2]; + System.arraycopy(this._g, 0, var13, 0, this._g.length); + this._g = var13; + } + + } + + if (var10 >= var4) { + var4 = 1 + var10; + } + this._g[var10] = ~i; + } + } + } + + private int decode(final byte[] src, final int srcOffset, final int len, final byte[] dest) { + if (len == 0) { + return 0; + } + + int var6 = 0; + int var7 = 0; + int var8 = srcOffset; + while (true) { + final byte var9 = src[var8]; + if (var9 >= 0) { + ++var7; + } else { + var7 = this._g[var7]; + } + + int var10; + if ((var10 = this._g[var7]) < 0) { + dest[var6++] = (byte) (~var10); + if (var6 >= len) { + break; + } + + var7 = 0; + } + + if ((64 & var9) == 0) { + ++var7; + } else { + var7 = this._g[var7]; + } + + if ((var10 = this._g[var7]) < 0) { + dest[var6++] = (byte) (~var10); + if (len <= var6) { + break; + } + + var7 = 0; + } + + if ((32 & var9) == 0) { + ++var7; + } else { + var7 = this._g[var7]; + } + + if ((var10 = this._g[var7]) < 0) { + dest[var6++] = (byte) (~var10); + if (len <= var6) { + break; + } + + var7 = 0; + } + + if ((var9 & 16) == 0) { + ++var7; + } else { + var7 = this._g[var7]; + } + + if ((var10 = this._g[var7]) < 0) { + dest[var6++] = (byte) (~var10); + if (var6 >= len) { + break; + } + + var7 = 0; + } + + if ((var9 & 8) == 0) { + ++var7; + } else { + var7 = this._g[var7]; + } + + if ((var10 = this._g[var7]) < 0) { + dest[var6++] = (byte) (~var10); + if (var6 >= len) { + break; + } + + var7 = 0; + } + + if ((4 & var9) == 0) { + ++var7; + } else { + var7 = this._g[var7]; + } + + if ((var10 = this._g[var7]) < 0) { + dest[var6++] = (byte) (~var10); + if (len <= var6) { + break; + } + + var7 = 0; + } + + if ((2 & var9) == 0) { + ++var7; + } else { + var7 = this._g[var7]; + } + + if ((var10 = this._g[var7]) < 0) { + dest[var6++] = (byte) (~var10); + if (len <= var6) { + break; + } + + var7 = 0; + } + + if ((var9 & 1) == 0) { + ++var7; + } else { + var7 = this._g[var7]; + } + + if ((var10 = this._g[var7]) < 0) { + dest[var6++] = (byte) (~var10); + if (var6 >= len) { + break; + } + + var7 = 0; + } + + ++var8; + } + + return 1 + var8 - srcOffset; + } + + private int encode(final byte[] dest, final int destOffset, final byte[] src, final int len) { + int var7 = 0; + int var8 = destOffset << 3; + + for (int srcPos = 0; srcPos < len; ++srcPos) { + final int byteToEncode = src[srcPos] & 255; + final int var10 = this._a[byteToEncode]; + final byte var11 = this.codes[byteToEncode]; + if (var11 == 0) { + throw new RuntimeException("" + byteToEncode); + } + + int destPos = var8 >> 3; + int var13 = var8 & 0b111; + var7 &= -var13 >> 31; + final int var14 = destPos + ((var11 + var13 - 1) >> 3); + var8 += var11; + var13 += 24; + dest[destPos] = (byte) (var7 = var7 | (var10 >>> var13)); + if (destPos < var14) { + ++destPos; + var13 -= 8; + dest[destPos] = (byte) (var7 = var10 >>> var13); + if (destPos < var14) { + var13 -= 8; + ++destPos; + dest[destPos] = (byte) (var7 = var10 >>> var13); + if (destPos < var14) { + var13 -= 8; + ++destPos; + dest[destPos] = (byte) (var7 = var10 >>> var13); + if (destPos < var14) { + var13 -= 8; + ++destPos; + dest[destPos] = (byte) (var7 = var10 << -var13); + } + } + } + } + } + + return (var8 + 0b111 >> 3) - destOffset; + } + + @SuppressWarnings("SameParameterValue") + public synchronized @NotNull String readEncoded(final @NotNull Buffer buffer, final int maxLen) { + final int len = Math.min(buffer.readVariable8_16(), maxLen); + final byte[] data = new byte[len]; + buffer.pos += this.decode(buffer.data, buffer.pos, len, data); + return Strings.decode1252String(data, 0, len); + } + + public synchronized @NotNull String readEncoded(final @NotNull Packet buffer, final int len) { + final int startPos = buffer.readerIndex(); + final int strLen = buffer.readVariable8_16(); + final byte[] encoded = new byte[len - (buffer.readerIndex() - startPos)]; + buffer.readBytes(encoded); + final byte[] decoded = new byte[strLen]; + this.decode(encoded, 0, strLen, decoded); + return Strings.decode1252String(decoded); + } + + @SuppressWarnings("SameParameterValue") + public synchronized void writeEncoded(final @NotNull CipheredBuffer buffer, final @NotNull String str) { + final byte[] data = Strings.encode1252String(str); + buffer.writeVariable8_16(data.length); + buffer.pos += this.encode(buffer.data, buffer.pos, data, data.length); + } + + public synchronized void writeEncoded(final @NotNull Packet buffer, final @NotNull String str) { + final byte[] decoded = Strings.encode1252String(str); + buffer.writeVariable8_16(decoded.length); + final byte[] encoded = new byte[256]; + final int len = this.encode(encoded, 0, decoded, decoded.length); + buffer.writeBytes(encoded, len); + } +} diff --git a/src/main/java/funorb/io/Inflater.java b/src/main/java/funorb/io/Inflater.java new file mode 100644 index 0000000..7a7feb9 --- /dev/null +++ b/src/main/java/funorb/io/Inflater.java @@ -0,0 +1,21 @@ +package funorb.io; + +public final class Inflater { + private static final java.util.zip.Inflater INFLATER = new java.util.zip.Inflater(true); + + private Inflater() {} + + public static synchronized void inflate(final Buffer src, final byte[] dest) { + if (src.data[src.pos] != 31 || src.data[src.pos + 1] != -117) { + throw new RuntimeException("bad magic"); + } + try { + INFLATER.setInput(src.data, src.pos + 10, src.data.length - (src.pos + 8) - 10); + INFLATER.inflate(dest); + } catch (final Exception e) { + throw new RuntimeException(e); + } finally { + INFLATER.reset(); + } + } +} diff --git a/src/main/java/funorb/io/Packet.java b/src/main/java/funorb/io/Packet.java new file mode 100644 index 0000000..17f2f41 --- /dev/null +++ b/src/main/java/funorb/io/Packet.java @@ -0,0 +1,209 @@ +package funorb.io; + +import funorb.Strings; +import funorb.shatteredplans.S2CPacket; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.util.ReferenceCounted; +import org.jetbrains.annotations.NotNull; + +import java.util.zip.CRC32; + +public final class Packet implements ReferenceCounted, ReadableBuffer, WritableBuffer { + public static final Packet S2C_KEEPALIVE = new Packet(S2CPacket.Type.KEEPALIVE, PacketLengthType.FIXED, Unpooled.EMPTY_BUFFER); + public static final Packet S2C_ENTER_MP = new Packet(S2CPacket.Type.ENTER_MP, PacketLengthType.FIXED, Unpooled.EMPTY_BUFFER); + public static final Packet S2C_LEAVE_MP = new Packet(S2CPacket.Type.LEAVE_MP, PacketLengthType.FIXED, Unpooled.EMPTY_BUFFER); + public static final Packet S2C_LEAVE_GAME = new Packet(S2CPacket.Type.LEAVE_GAME, PacketLengthType.FIXED, Unpooled.EMPTY_BUFFER); + + public final int type; + public final boolean typeIsCiphered; + public final PacketLengthType lengthType; + public final ByteBuf payload; + + @SuppressWarnings("WeakerAccess") + public Packet(final int type, final boolean typeIsCiphered, final PacketLengthType lengthType, final ByteBuf payload) { + this.type = type; + this.typeIsCiphered = typeIsCiphered; + this.lengthType = lengthType; + this.payload = payload; + } + + public Packet(final int type, final PacketLengthType lengthType, final ByteBuf payload) { + this(type, true, lengthType, payload); + } + + public Packet retainedSlice() { + return new Packet(this.type, this.typeIsCiphered, this.lengthType, this.payload.retainedSlice()); + } + + @Override + public int refCnt() { + return this.payload.refCnt(); + } + + @Override + public Packet retain() { + this.payload.retain(); + return this; + } + + @Override + public Packet retain(final int increment) { + this.payload.retain(increment); + return this; + } + + @Override + public Packet touch() { + return this; + } + + @Override + public Packet touch(final Object hint) { + return this; + } + + @Override + public boolean release() { + return this.payload.release(); + } + + @Override + public boolean release(final int decrement) { + return this.payload.release(decrement); + } + + @Override + public int readerIndex() { + return this.payload.readerIndex(); + } + + public int readableBytes() { + return this.payload.readableBytes(); + } + + @SuppressWarnings("unused") + @Override + public void skipBytes(final int len) { + this.payload.skipBytes(len); + } + + @SuppressWarnings("unused") + @Override + public byte readByte() { + return this.payload.readByte(); + } + + @Override + public int readUByte() { + return this.payload.readUnsignedByte(); + } + + @Override + public int readUShort() { + return this.payload.readUnsignedShort(); + } + + @Override + public int readInt() { + return this.payload.readInt(); + } + + @SuppressWarnings("unused") + @Override + public long readLong() { + return this.payload.readLong(); + } + + @Override + public int readVariable8_16() { + final int nextByte = this.payload.getByte(this.payload.readerIndex()); + if ((nextByte & 0x80) == 0) { + return this.readUByte(); + } else { + return this.readUShort() - 0x8000; + } + } + + @SuppressWarnings("unused") + @Override + public void readBytes(final byte[] dest, final int len) { + this.payload.readBytes(dest, 0, len); + } + + @Override + public @NotNull String readNullTerminatedString() { + final int len = this.payload.bytesBefore((byte) 0); + final byte[] bytes = new byte[len]; + this.payload.readBytes(bytes); + this.payload.readByte(); + return Strings.decode1252String(bytes); + } + + @SuppressWarnings("unused") + @Override + public @NotNull String readNullBracketedString() { + if (this.payload.readByte() != 0) { + throw new IllegalStateException("expected leading 0"); + } + return this.readNullTerminatedString(); + } + + @Override + public void writeByte(final int val) { + this.payload.writeByte(val); + } + + @Override + public void writeShort(final int val) { + this.payload.writeShort(val); + } + + @Override + public void writeInt(final int val) { + this.payload.writeInt(val); + } + + @Override + public void writeLong(final long val) { + this.payload.writeLong(val); + } + + @SuppressWarnings("unused") + @Override + public void writeBytes(final byte[] data) { + this.payload.writeBytes(data); + } + + @Override + public void writeBytes(final byte[] data, final int len) { + this.payload.writeBytes(data, 0, len); + } + + @Override + public void writeVariableInt(final int val) { + if (val >= (1 << 21)) this.payload.writeByte( (val >>> 21) | 0x80); + if (val >= (1 << 14)) this.payload.writeByte(((val >>> 14) & 0x7f) | 0x80); + if (val >= (1 << 7)) this.payload.writeByte(((val >>> 7) & 0x7f) | 0x80); + this.payload.writeByte(val & 0x7f); + } + + @Override + public void writeNullTerminatedString(final String str) { + this.payload.writeBytes(Strings.encode1252String(str)); + this.writeByte(0); + } + + @Override + public void writeNullBracketedString(final String str) { + this.writeByte(0); + this.writeNullTerminatedString(str); + } + + @Override + public void writeCRC(final int len) { + final CRC32 crc = new CRC32(); + crc.update(this.payload.nioBuffer(this.payload.writerIndex() - len, len)); + this.writeInt((int) crc.getValue()); + } +} diff --git a/src/main/java/funorb/io/PacketLengthType.java b/src/main/java/funorb/io/PacketLengthType.java new file mode 100644 index 0000000..eef266e --- /dev/null +++ b/src/main/java/funorb/io/PacketLengthType.java @@ -0,0 +1,16 @@ +package funorb.io; + +public enum PacketLengthType { + FIXED(0), + VARIABLE_BYTE(1), + VARIABLE_SHORT(2); + + public static final int VARIABLE_BYTE_I = -1; + public static final int VARIABLE_SHORT_I = -2; + + public final int length; + + PacketLengthType(final int length) { + this.length = length; + } +} diff --git a/src/main/java/funorb/io/ReadableBuffer.java b/src/main/java/funorb/io/ReadableBuffer.java new file mode 100644 index 0000000..02d0075 --- /dev/null +++ b/src/main/java/funorb/io/ReadableBuffer.java @@ -0,0 +1,39 @@ +package funorb.io; + +import org.jetbrains.annotations.NotNull; + +@SuppressWarnings({"SameParameterValue", "unused"}) +public interface ReadableBuffer { + int readerIndex(); + + void skipBytes(int len); + + byte readByte(); + + int readUByte(); + + int readUShort(); + + int readInt(); + + long readLong(); + + default int readU24() { + final int b1 = this.readUByte(); + final int b2 = this.readUByte(); + final int b3 = this.readUByte(); + return (b1 << 16) + (b2 << 8) + b3; + } + + int readVariable8_16(); + + void readBytes(byte[] dest, int len); + + default void readBytes(final byte[] dest) { + this.readBytes(dest, dest.length); + } + + @NotNull String readNullTerminatedString(); + + @NotNull String readNullBracketedString(); +} diff --git a/src/main/java/funorb/io/WritableBuffer.java b/src/main/java/funorb/io/WritableBuffer.java new file mode 100644 index 0000000..07aa1c9 --- /dev/null +++ b/src/main/java/funorb/io/WritableBuffer.java @@ -0,0 +1,43 @@ +package funorb.io; + +@SuppressWarnings({"SameParameterValue", "unused"}) +public interface WritableBuffer { + void writeByte(int val); + + void writeShort(int val); + + void writeInt(int val); + + void writeLong(long val); + + default void writeU24(final int val) { + if (val < 0 || val > 0xffffff) { + throw new IllegalArgumentException("argument does not fit into 24 bits: 0x" + Integer.toHexString(val)); + } + this.writeByte((val >>> 16) & 0xff); + this.writeByte((val >>> 8) & 0xff); + this.writeByte(val & 0xff); + } + + void writeVariableInt(int val); + + default void writeVariable8_16(final int val) { + if (val >= 0 && val < 128) { + this.writeByte(val); + } else if (val >= 0 && val < 0x8000) { + this.writeShort(val + 0x8000); + } else { + throw new IllegalArgumentException("argument does not fit into 15 bits: 0x" + Integer.toHexString(val)); + } + } + + void writeBytes(byte[] data); + + void writeBytes(byte[] data, int len); + + void writeNullTerminatedString(String str); + + void writeNullBracketedString(String str); + + void writeCRC(int len); +} diff --git a/src/main/java/funorb/net/ProtocolException.java b/src/main/java/funorb/net/ProtocolException.java new file mode 100644 index 0000000..b0981c1 --- /dev/null +++ b/src/main/java/funorb/net/ProtocolException.java @@ -0,0 +1,23 @@ +package funorb.net; + +public final class ProtocolException extends RuntimeException { + @SuppressWarnings("unused") + public ProtocolException() { + super(); + } + + @SuppressWarnings("unused") + public ProtocolException(final String message) { + super(message); + } + + @SuppressWarnings("unused") + public ProtocolException(final String message, final Throwable cause) { + super(message, cause); + } + + @SuppressWarnings("unused") + public ProtocolException(final Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/funorb/shatteredplans/C2SPacket.java b/src/main/java/funorb/shatteredplans/C2SPacket.java new file mode 100644 index 0000000..ee262e4 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/C2SPacket.java @@ -0,0 +1,280 @@ +package funorb.shatteredplans; + +import funorb.client.RankingsRequest; +import funorb.client.SetProfileRequest; +import funorb.client.lobby.ChatMessage; +import funorb.io.CipheredBuffer; +import funorb.io.HuffmanCoder; +import funorb.io.PacketLengthType; +import funorb.shatteredplans.client.JagexApplet; +import funorb.shatteredplans.client.ShatteredPlansClient; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; + +import java.util.Optional; + +public final class C2SPacket { + public static final CipheredBuffer buffer = new CipheredBuffer(); + + public static void goodbye() { + Type.DISCONNECT.write(buffer); + } + + public static void a093bo() { + Type.ACHIEVEMENTS.write(buffer); + buffer.writeByte(1); + buffer.writeByte(2); + } + + public static void sendProfileGet() { + Type.PROFILE.write(buffer); + buffer.writeBytes(1, ProfileAction.GET); + } + + public static void sendProfileSet(final SetProfileRequest var1) { + Type.PROFILE.write(buffer); + buffer.withLengthByte(() -> { + final int startPos = buffer.pos; + buffer.writeByte(ProfileAction.SET); + if (var1.data == null) { + buffer.writeByte(0); + } else { + buffer.writeByte(var1.data.length); + buffer.writeBytes(var1.data); + } + + buffer.writeDigest(startPos); + buffer.pos -= 4; + var1.digest = buffer.readInt(); + }); + } + + public static void a970uf(final RankingsRequest var0) { + Type.RANKING.write(buffer); + buffer.writeByte(var0._k); + buffer.writeByte(var0._j); + } + + public static void enterLobby() { + Type.ENTER_MP.write(buffer); + } + + public static void leaveLobby() { + Type.LEAVE_MP.write(buffer); + } + + private static void sendLobbyAction(final int type, final Runnable writePayload) { + Type.LOBBY.write(buffer); + buffer.withLengthByte(() -> { + buffer.writeByte(type); + writePayload.run(); + }); + } + + public static void playRatedGame() { + sendLobbyAction(LobbyAction.PLAY_RATED_GAME, () -> {}); + } + + public static void returnToLobby() { + sendLobbyAction(LobbyAction.RETURN_TO_LOBBY, () -> {}); + } + + public static void updateRatedGamePreferences(final byte[] a, final int b, final int c, final byte[] d) { + sendLobbyAction(LobbyAction.SET_RATED_OPTIONS, () -> { + buffer.writeBytes(a); + buffer.writeByte(b); + buffer.writeByte(c); + buffer.writeBytes(d); + }); + } + + public static void acknowledgeRatedRoomInfo() { + sendLobbyAction(LobbyAction.ACK_RATED_ROOM_INFO, () -> {}); + } + + public static void createUnratedGame() { + sendLobbyAction(LobbyAction.CREATE_UNRATED_GAME, () -> buffer.writeBytes(6, 128, 4, 2, 0, 2, 0)); + } + + public static void updateRoomOptions() { + sendLobbyAction(LobbyAction.SET_ROOM_OPTIONS, () -> { + buffer.writeByte(ShatteredPlansClient.unratedLobbyRoom.maxPlayerCount); + buffer.writeByte((ShatteredPlansClient.unratedLobbyRoom.allowSpectate << 6) + ShatteredPlansClient.unratedLobbyRoom.whoCanJoin); + buffer.writeBytes(ShatteredPlansClient.unratedLobbyRoom.gameSpecificOptions); + }); + } + + public static void inviteToGame(final long player) { + sendLobbyAction(LobbyAction.INVITE_PLAYER_TO_GAME, () -> buffer.writeLong(player)); + } + + public static void kickFromGame(final long player) { + sendLobbyAction(LobbyAction.KICK_PLAYER_FROM_GAME, () -> buffer.writeLong(player)); + } + + public static void requestToJoinRoom(final int game) { + sendLobbyAction(LobbyAction.JOIN_ROOM, () -> buffer.writeShort(game)); + } + + public static void requestToLeaveRoom(final int game) { + sendLobbyAction(LobbyAction.LEAVE_ROOM, () -> buffer.writeShort(game)); + } + + public static void spectateGame(final int game) { + sendLobbyAction(LobbyAction.SPECTATE_GAME, () -> buffer.writeShort(game)); + } + + public static void showPlayersInGame(final int game) { + sendLobbyAction(LobbyAction.SHOW_PLAYERS_IN_GAME, () -> buffer.writeShort(game)); + } + + public static void friendIgnore(final int what, final String who) { + Type.SOCIAL.write(buffer); + buffer.withLengthByte(() -> { + buffer.writeByte(what); + buffer.writeNullTerminatedString(who); + }); + } + + public static void sendChatMessage(final @NotNull ChatMessage.Channel channel, final String recipientName, final @NotNull String message) { + Type.CHAT.write(buffer); + buffer.withLengthByte(() -> { + buffer.writeByte(channel.encode()); + if (channel == ChatMessage.Channel.PRIVATE) { + buffer.writeNullTerminatedString(recipientName); + } + HuffmanCoder.instance.writeEncoded(buffer, message); + }); + } + + public static void sendQuickChatMessage(final @NotNull ChatMessage.Channel channel, final String recipientName, final int messageId) { + Type.QUICK_CHAT.write(buffer); + buffer.withLengthByte(() -> { + buffer.writeByte(channel.encode()); + if (channel == ChatMessage.Channel.PRIVATE) { + buffer.writeNullTerminatedString(recipientName); + } + buffer.writeShort(messageId); + }); + } + + public static void setChatFilters(final int filters) { + Type.SOCIAL.write(buffer); + buffer.withLengthByte(() -> { + buffer.writeByte(4); + buffer.writeByte(filters); + }); + } + + public static void reportAbuse(final long var0, final boolean var3, final String var4, final int var5) { + Type.REPORT.write(buffer); + buffer.withLengthByte(() -> { + buffer.writeLong(var0); + buffer.writeNullTerminatedString(var4); + buffer.writeByte(var5); + buffer.writeByte(var3 ? 1 : 0); + }); + } + + public static void sendViewMessages() { + Type.VIEW_MESSAGES.write(buffer); + } + + public static void a115vf2() { + buffer.writeCipheredByte(18); + buffer.withLengthByte(() -> buffer.writeBytes(JagexApplet.loginPacket.data, JagexApplet.loginPacket.pos)); + } + + public static void send58() { + Type.START_GAME.write(buffer); + } + + public enum Type { + KEEPALIVE (0x00, 0), + DISCONNECT (0x01, 0), + LEVEL_KEY (0x02, 3), + HIGHSCORE (0x03, PacketLengthType.VARIABLE_BYTE_I), + ACHIEVEMENTS (0x04, PacketLengthType.VARIABLE_BYTE_I), + PROGRESS (0x05, PacketLengthType.VARIABLE_BYTE_I), + PROFILE (0x06, PacketLengthType.VARIABLE_BYTE_I), + RANKING (0x07, 2), + REFLECT (0x08, PacketLengthType.VARIABLE_BYTE_I), + ENTER_MP (0x09, 0), + LEAVE_MP (0x0a, 0), + LOBBY (0x0b, PacketLengthType.VARIABLE_BYTE_I), + CHAT (0x0c, PacketLengthType.VARIABLE_BYTE_I), + SOCIAL (0x0d, PacketLengthType.VARIABLE_BYTE_I), + REPORT (0x0e, PacketLengthType.VARIABLE_BYTE_I), + QUICK_CHAT (0x0f, PacketLengthType.VARIABLE_BYTE_I), + COMPLETE (0x10, PacketLengthType.VARIABLE_BYTE_I), + VIEW_MESSAGES (0x11, 0), + BIRTH (0x12, PacketLengthType.VARIABLE_BYTE_I), + START_GAME (0x3a, 0), + ORDERS (0x3b, PacketLengthType.VARIABLE_SHORT_I), + ALL_TURN_ORDERS (0x3c, PacketLengthType.VARIABLE_SHORT_I), + END_TURN (0x3d, 5), + CANCEL_END_TURN (0x3e, 1), + OFFER_DRAW (0x3f, 0), + RESIGN (0x40, 0), + OFFER_REMATCH (0x41, 0), + DESYNC (0x42, PacketLengthType.VARIABLE_SHORT_I); + + private static final Type[] BY_ID = new Type[256]; + static { + for (final Type type : values()) { + assert BY_ID[type.id] == null; + BY_ID[type.id] = type; + } + } + + public static Optional lookup(final @Range(from=0, to=0xff) int id) { + return Optional.ofNullable(BY_ID[id]); + } + + public final byte id; + public final int length; + public final PacketLengthType lengthType; + + Type(final int id, final int length) { + this.id = (byte) id; + this.length = length; + this.lengthType = switch (length) { + case PacketLengthType.VARIABLE_BYTE_I -> PacketLengthType.VARIABLE_BYTE; + case PacketLengthType.VARIABLE_SHORT_I -> PacketLengthType.VARIABLE_SHORT; + default -> PacketLengthType.FIXED; + }; + } + + public void write(final CipheredBuffer buffer) { + buffer.writeCipheredByte((int) this.id & 0xff); + } + } + + @SuppressWarnings("WeakerAccess") + public static final class ProfileAction { + public static final int GET = 0; + public static final int SET = 1; + } + + @SuppressWarnings("WeakerAccess") + public static final class LobbyAction { + public static final int PLAY_RATED_GAME = 0; + public static final int RETURN_TO_LOBBY = 1; + public static final int SET_RATED_OPTIONS = 2; + public static final int ACK_RATED_ROOM_INFO = 3; + public static final int CREATE_UNRATED_GAME = 4; + public static final int SET_ROOM_OPTIONS = 5; + public static final int INVITE_PLAYER_TO_GAME = 6; + public static final int KICK_PLAYER_FROM_GAME = 7; + public static final int JOIN_ROOM = 8; + public static final int LEAVE_ROOM = 9; + public static final int SPECTATE_GAME = 10; + public static final int SHOW_PLAYERS_IN_GAME = 11; + } + + public static final class OrderType { + public static final int BUILD = 192; + public static final int PROJECT = 251; + public static final int PACT = 255; + } +} diff --git a/src/main/java/funorb/shatteredplans/CacheFiles.java b/src/main/java/funorb/shatteredplans/CacheFiles.java new file mode 100644 index 0000000..20bf66a --- /dev/null +++ b/src/main/java/funorb/shatteredplans/CacheFiles.java @@ -0,0 +1,39 @@ +package funorb.shatteredplans; + +import funorb.cache.CacheFile; + +import java.io.Closeable; +import java.io.IOException; + +public final class CacheFiles implements Closeable { + public final CacheFile random; + public final CacheFile data; + public final CacheFile masterIndex; + public final CacheFile[] indexes; + + public CacheFiles() { + try { + this.random = new CacheFile(CacheFile.path("random.dat", null), 25L); + this.data = new CacheFile(CacheFile.path("main_file_cache.dat2"), 0x12c00000L); + this.masterIndex = new CacheFile(CacheFile.path("main_file_cache.idx255"), 0x100000L); + this.indexes = new CacheFile[15]; + for (int i = 0; i < this.indexes.length; ++i) { + //noinspection resource + this.indexes[i] = new CacheFile(CacheFile.path("main_file_cache.idx" + i), 0x100000L); + } + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + + + @Override + public void close() throws IOException { + this.random.close(); + this.data.close(); + this.masterIndex.close(); + for (final CacheFile index : this.indexes) { + index.close(); + } + } +} diff --git a/src/main/java/funorb/shatteredplans/S2CPacket.java b/src/main/java/funorb/shatteredplans/S2CPacket.java new file mode 100644 index 0000000..2033cb7 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/S2CPacket.java @@ -0,0 +1,220 @@ +package funorb.shatteredplans; + +import funorb.client.lobby.ChatMessage; +import funorb.io.HuffmanCoder; +import funorb.io.Packet; +import funorb.io.PacketLengthType; +import io.netty.buffer.ByteBufAllocator; +import org.jetbrains.annotations.NotNull; + +import static funorb.io.PacketLengthType.VARIABLE_BYTE_I; +import static funorb.io.PacketLengthType.VARIABLE_SHORT_I; +import static funorb.shatteredplans.S2CPacket.Type.*; + +public final class S2CPacket { + public static final int[] LENGTH = new int[256]; + static { + LENGTH[0x01] = 16; + LENGTH[0x02] = VARIABLE_SHORT_I; + LENGTH[ACHIEVEMENTS] = VARIABLE_BYTE_I; + LENGTH[0x04] = VARIABLE_BYTE_I; + LENGTH[PROFILE] = VARIABLE_BYTE_I; + LENGTH[RATINGS] = VARIABLE_SHORT_I; + LENGTH[SESSION_ID] = VARIABLE_BYTE_I; + LENGTH[REFLECT] = VARIABLE_SHORT_I; + LENGTH[ERROR] = VARIABLE_BYTE_I; + LENGTH[LOBBY] = VARIABLE_BYTE_I; + LENGTH[CHAT] = VARIABLE_BYTE_I; + LENGTH[QUICK_CHAT] = VARIABLE_BYTE_I; + LENGTH[SOCIAL] = VARIABLE_BYTE_I; + LENGTH[DISPLAY_NAME] = VARIABLE_BYTE_I; + LENGTH[SHOW_DOCUMENT] = VARIABLE_BYTE_I; + LENGTH[DISABLE_CHAT_RESTRICTIONS] = 1; + LENGTH[ENTER_GAME] = VARIABLE_SHORT_I; + LENGTH[VICTORY] = 1; + LENGTH[DRAW_OFFERS] = 1; + LENGTH[RESIGNATIONS] = 1; + LENGTH[REMATCH_OFFERS] = 1; + LENGTH[PLAYERS_LEFT] = 1; + LENGTH[ADVANCE_TURN] = 15; + LENGTH[TURN_ORDERS] = VARIABLE_SHORT_I; + LENGTH[DIPLOMATIC_PACTS] = VARIABLE_BYTE_I; + LENGTH[PLAYERS_WAITING_ON] = 1; + LENGTH[TURN_ORDERS_AND_UPDATE] = VARIABLE_SHORT_I; + LENGTH[0x47] = 4; + LENGTH[0x48] = 0; + LENGTH[AI_CHAT] = 3; + LENGTH[0x4a] = VARIABLE_SHORT_I; + } + + public static final boolean[] MGS_ENABLED = new boolean[64]; + static { + MGS_ENABLED[KEEPALIVE] = true; + MGS_ENABLED[ACHIEVEMENTS] = true; + MGS_ENABLED[PROFILE] = true; + MGS_ENABLED[RATINGS] = true; + MGS_ENABLED[SESSION_ID] = true; + MGS_ENABLED[REFLECT] = true; + MGS_ENABLED[CHAT] = true; + MGS_ENABLED[QUICK_CHAT] = true; + MGS_ENABLED[SOCIAL] = true; + MGS_ENABLED[DISPLAY_NAME] = true; + MGS_ENABLED[SHOW_DOCUMENT] = true; + MGS_ENABLED[DISABLE_CHAT_RESTRICTIONS] = true; + } + + public static Packet lobbyChatMessage(final @NotNull ByteBufAllocator alloc, + final long senderId, + final @NotNull String senderName, + final @NotNull String senderDisplayName, + final @NotNull String message) { + final Packet packet = new Packet(CHAT, PacketLengthType.VARIABLE_BYTE, alloc.buffer()); + try { + packet.writeByte(ChatMessage.Channel.LOBBY.encode()); + packet.writeByte(0); // some sort of image prefix? + packet.writeLong(senderId); + + final boolean separateDisplayName = !senderName.equals(senderDisplayName); + packet.writeByte(separateDisplayName ? 1 : 0); + packet.writeNullTerminatedString(senderDisplayName); + if (separateDisplayName) { + packet.writeNullTerminatedString(senderName); + } + + HuffmanCoder.instance.writeEncoded(packet, message); + return packet.retain(); + } finally { + packet.release(); + } + } + + public static Packet roomChatMessage(final @NotNull ByteBufAllocator alloc, + final int roomId, + final @NotNull String gameOwnerDisplayName, + final long senderId, + final @NotNull String senderName, + final @NotNull String senderDisplayName, + final @NotNull String message) { + final Packet packet = new Packet(CHAT, PacketLengthType.VARIABLE_BYTE, alloc.buffer()); + try { + packet.writeByte(ChatMessage.Channel.ROOM.encode()); + packet.writeByte(0); // some sort of image prefix? + packet.writeLong(senderId); + + final boolean separateDisplayName = !senderName.equals(senderDisplayName); + packet.writeByte(separateDisplayName ? 1 : 0); + packet.writeNullTerminatedString(senderDisplayName); + if (separateDisplayName) { + packet.writeNullTerminatedString(senderName); + } + + packet.writeShort(roomId); + packet.writeNullTerminatedString(gameOwnerDisplayName); + + HuffmanCoder.instance.writeEncoded(packet, message); + return packet.retain(); + } finally { + packet.release(); + } + } + + public static Packet privateChatMessage(final @NotNull ByteBufAllocator alloc, + final long senderId, + final @NotNull String senderName, + final @NotNull String senderDisplayName, + final @NotNull String message) { + final Packet packet = new Packet(CHAT, PacketLengthType.VARIABLE_BYTE, alloc.buffer()); + try { + packet.writeByte(ChatMessage.Channel.PRIVATE.encode()); + packet.writeByte(0); // some sort of image prefix? + packet.writeLong(senderId); + + packet.writeShort(0); // not sure + packet.writeU24(0); // not sure + + final boolean separateDisplayName = !senderName.equals(senderDisplayName); + packet.writeByte(separateDisplayName ? 1 : 0); + packet.writeNullTerminatedString(senderDisplayName); + if (separateDisplayName) { + packet.writeNullTerminatedString(senderName); + } + + HuffmanCoder.instance.writeEncoded(packet, message); + return packet.retain(); + } finally { + packet.release(); + } + } + + public static final class Type { + public static final int KEEPALIVE = 0x00; + public static final int XTEA = 0x01; + public static final int HISCORE = 0x02; + public static final int ACHIEVEMENTS = 0x03; + public static final int LEVEL_PROGRESS = 0x04; + public static final int PROFILE = 0x05; + public static final int RATINGS = 0x06; + public static final int SESSION_ID = 0x07; + public static final int REFLECT = 0x08; + public static final int ERROR = 0x09; + public static final int LOBBY = 0x0a; + public static final int CHAT = 0x0b; + public static final int QUICK_CHAT = 0x0c; + public static final int SOCIAL = 0x0d; + public static final int ENTER_MP = 0x0e; + public static final int LEAVE_MP = 0x0f; + public static final int DISPLAY_NAME = 0x10; + public static final int SHOW_DOCUMENT = 0x11; + public static final int DISABLE_CHAT_RESTRICTIONS = 0x12; + public static final int ENTER_GAME = 0x3a; + public static final int LEAVE_GAME = 0x3c; + public static final int VICTORY = 0x3d; + public static final int DRAW_OFFERS = 0x3e; + public static final int RESIGNATIONS = 0x3f; + public static final int REMATCH_OFFERS = 0x40; + public static final int PLAYERS_LEFT = 0x41; + public static final int ADVANCE_TURN = 0x42; + public static final int TURN_ORDERS = 0x43; + public static final int DIPLOMATIC_PACTS = 0x44; + public static final int PLAYERS_WAITING_ON = 0x45; + public static final int TURN_ORDERS_AND_UPDATE = 0x46; + public static final int ACHIEVEMENTS_UNLOCKED = 0x47; + public static final int RESEND_ALL_TURN_ORDERS = 0x48; + public static final int AI_CHAT = 0x49; + } + + public static final class SocialAction { + public static final int IGNORE = 0; + public static final int FRIEND = 1; + public static final int LOADED = 2; + public static final int LOADING = 3; + public static final int INITIALIZE = 4; + } + + public static final class LobbyAction { + public static final int YOU_LEFT_ROOM = 0; + public static final int YOU_WERE_KICKED = 1; + public static final int YOU_CREATED_RANKED_ROOM = 2; + public static final int YOU_JOINED_RANKED_ROOM = 3; + public static final int YOU_JOINED_ROOM = 4; + public static final int PLAYER_ENTERED_LOBBY = 5; + public static final int PLAYER_LEFT_LOBBY = 6; + public static final int REMOVE_ALL_JOIN_REQUESTS = 7; + public static final int ADD_ROOM = 8; + public static final int REMOVE_ROOM = 9; + public static final int REMOVE_ALL_ROOMS = 10; + public static final int YOU_ARE_INVITED = 11; + public static final int YOU_SENT_JOIN_REQUEST = 12; + public static final int ROOM_STATUS = 13; + public static final int ADD_PLAYER_INVITE = 14; + public static final int REMOVE_PLAYER_INVITE = 15; + public static final int ADD_PLAYER_JOIN_REQUEST = 16; + public static final int REMOVE_PLAYER_JOIN_REQUEST = 17; + public static final int PLAYER_JOINED_ROOM = 18; + public static final int PLAYER_LEFT_ROOM = 19; + public static final int ROOM_INFO = 20; + public static final int GAME_OPTIONS_CHANGED = 21; + public static final int RATING = 22; + public static final int PLAYER_ID = 23; + } +} diff --git a/src/main/java/funorb/shatteredplans/StringConstants.java b/src/main/java/funorb/shatteredplans/StringConstants.java new file mode 100644 index 0000000..d15ce1e --- /dev/null +++ b/src/main/java/funorb/shatteredplans/StringConstants.java @@ -0,0 +1,1517 @@ +package funorb.shatteredplans; + +import funorb.Strings; +import funorb.cache.ResourceLoader; +import funorb.client.lobby.ReportAbuseDialog; + +import java.util.function.Consumer; + +public final class StringConstants { + public static final String[] RESOURCE_NAMES = new String[]{"Metal", "Biomass", "Energy", "Exotics"}; + public static final String[] INSTRUCTIONS_TABNAMES = new String[]{"Overview", "Glossary I", "Glossary II", "Tactical Display", "System HUD", "Controls I", "Controls II", "Animations", "Projects", "Game Types", "Classic Rules"}; + public static final String[] TOOLTIP_INCOME = new String[]{"Metal income in this territory.", "Biomass income in this territory.", "Energy income in this territory.", "Exotics income in this territory."}; + public static final String[] ACHIEVEMENT_NAMES = new String[]{"Hammer Blow", "Crushing Assault", "Decisive Strike", "Valiant Defence", "Unchecked Expansion", "Rapid Expansion", "Explosive Growth", "Man of Peace", "Total War", "Coordinated Assault", "Historian", "Lightning War", "Historical Footnote", "Renowned Leader", "Legendary Leader", "Feared Warlord", "Fabled Emperor", "Unassailable Grip", "Vast Empire", "Archaeologist", "Master Tactician", "Thronecrusher", "Man of Science", "New Galactic Order", "Oracle of Time"}; + public static final String[] HS_MODE_NAMES = new String[]{"All scores", "My scores", "Best each"}; + public static final String[] ACHIEVEMENT_CRITERIA = new String[]{"Attack with 95% of your forces (minimum 50 fleets) against a single enemy system.", "Assault an enemy system with 10 times as many fleets (minimum 50) as are defending it.", "Damage or destroy 100 fleets in one turn.", "Hold a system against attack from three or more systems in the same turn.", "Win a game, taking at least one system per turn throughout.", "Take five systems in one turn.", "Take eight systems in one turn.", "Have a treaty with all players simultaneously, then go on to win the game (minimum: 4 players).", "Win a game, having never signed a treaty (minimum: 4 players).", "Attack an enemy system with aid from an ally.", "Be holding at least 2 neutral homeworlds at the start of turn 8.", "Win a Conquest game in 20 turns or fewer (minimum: 4 players).", "Win 5 Rated games.", "Win 10 Rated games.", "Win 25 Rated games.", "Win 50 Rated games.", "Win 100 Rated games.", "Win a Capture and Hold game without anyone else ever capturing Sol (minimum: 4 players).", "Win a Points game before anyone else reaches 80% of the target score (minimum: 4 players).", "Own all derelicts on the map at once (minimum: 4 players).", "Win a Rated game of each type consecutively.", "Own all player homeworlds simultaneously (minimum: 4 players).", "Deploy all four projects in one turn.", "Defeat a JMod, or someone else who has this achievement.", "Deploy your projects when the time is right."}; + public static final String[] RATING_MODE_NAMES = new String[]{"By rating", "By win percentage"}; + public static final String[] TURN_NAMES_1 = new String[]{"Shattered", "Freezing", "Scorching", "Lost", "Cold", "Sundered", "Burning", "Wandering", "Enduring", "Ancient", "Chaos", "Potent", "Reborn", "Unseen", "Golden", "Beckoning", "Silent", "Waning", "Dancing", "Quantum", "Glittering", "Blackened"}; + public static final String[] GAMEOPT_LABELS = new String[]{"Maximum AI players", "Turn Time (seconds)", "Game Type", "Galaxy Size", "Ruleset", "Movement Range"}; + public static final String[][] GAMEOPT_NAMES = new String[][]{new String[0], {"300", "180", "120", "90", "60", "45", "30"}, {"Conquest", "Sol", "Points", "Derelicts"}, {"Huge", "Large", "Medium", "Small", "Tiny"}, {"Streamlined", "Classic"}}; + public static final String[] PROJECT_NAMES = new String[]{"Defensive Net", "Terraforming", "Stellar Bomb", "Tannhäuser Project"}; + public static final String[] TURN_NAMES_2 = new String[]{"<%0> Souls", "<%0> Ships", "<%0> Suns", "the <%0> Moon", "<%0> Peace", "the <%0> War", "<%0> Stars", "the <%0> People", "the <%0> Lights", "the <%0> Gate", "<%0> Empires", "<%0> Worlds", "<%0> Shadow", "<%0> Thunder", "the <%0> Storm", "<%0> Night", "<%0> Triumphs", "<%0> Steel", "<%0> Dreams"}; + public static final String[] QUICK_CHAT_SHORTCUT_KEYS = new String[]{"[BACKSPACE]", "[HOME]", "[F9]", "[F10]", "[F11]", "[ESC]"}; + public static final String[][] AI_CHAT = new String[][]{{"We will not bow before such as you."}, {"We cannot ally with any who call <%largestplayer> a friend."}, {"You do not have sufficient might to deserve that honour."}, {"An alliance with <%you> does not fit into our expansion plans."}, {"While we could of course defeat you easily, the forces on our borders can be better used elsewhere."}, {"Agreed. Let <%largestplayer> tremble before our combined might."}, {"We shall stand together in the battles ahead."}, {"The forces deployed on our borders could be put to better use. Let us sign a non-agression pact immediately."}, {"Join with us, and together we can end the tyranny of <%largestplayer>."}, {"Unite with us; our two nations together as one would be a power unmatched."}, {"A wise decision. Such profitless conflict serves neither of us."}, {"Excellent. We will begin mobilizing our forces against <%largestplayer> immediately."}, {"Excellent. Let us coordinate our battle plans."}, {"Time has yet to erase the mistakes of <%you>."}, {"The <%me> claims this portion of the galaxy. Defend yourself."}, {"The <%me> shall guard its borders carefully."}, {"We are the <%me>, and we are prepared for combat."}, {"The <%me> looks forward to an era of enlightened peace and prosperity."}, {"Do not attempt to interfere with the plans of <%me>."}, {"These resources will be of use in the struggle ahead.", "The citizens of <%system> are adjusting well to their new leadership."}, {"The defences at <%system> are strong indeed."}, {"<%system> will remain mine for all time!"}, {"Attacking <%system> was a tactical error."}, {"<%system> would be a prize indeed."}, {"You have no chance to survive, make your time.", "Your fall is now inevitable.", "Rest assured - your cultural artefacts will be preserved after your civilization collapses."}, {"No! This will not be tolerated!"}, {"Cease this useless violence!"}}; + public static final String[] TEXT_ORDINALS = new String[]{"1st", "2nd", "3rd", "4th", "5th", "6th"}; + public static final String[] AI_TYPES = new String[]{"(Old) Standard", "(Old) Cautious", "Tutorial", "Standard", "Aggressive", "Reckless", "Isolationist", "Defensive", "Task"}; + public static final String[] GAME_TYPE_TOOLTIPS = new String[]{"Destroy all opposition to reign supreme.", "Capture and hold Sol to earn points. Most points after 20 turns wins.", "Capture and hold systems to earn points.", "Capture derelict alien ships and research their secrets."}; + public static final String[] RULESET_TOOLTIPS = new String[]{"No garrisoning, production unified across territories.", "Garrisoning required, separate production per territory."}; + public static final String[] TEXT_INTRO_0 = new String[]{"New Cambridge Colony", "Historical Archives"}; + public static final String[] QUICK_CHAT_SHORTCUT_HELP = new String[]{"Move back to the previous menu level.", "Return to the top level of the menu.", "Auto-respond to the last thing in your chat window.", "Open the Quick Chat menu.", "Repeat the last thing you said.", "Close the Quick Chat menu."}; + public static final String[] EMPIRE_NAMES = new String[]{"Red Coalition", "Green Empire", "Blue Confederacy", "Magenta Union", "Yellow Imperium", "Cyan League"}; + public static String DERELICT = "Derelict"; + public static String TEXT_STAT_SHIPS_LOST = "Fleets lost"; + public static String CREATE_ALERT_NAME_CHARS = "Names can only contain letters, numbers, spaces and underscores"; + public static String VICTORY_TURNS_REMAINING = "Turns remaining: <%0>"; + public static String CREATE_ALERT_INVALID_AGE = "Please enter your age in years"; + public static String CREATE_ALERT_PASS_REPEATED = "This password contains repeated characters, and would be easy to guess"; + public static String CREATE_ALERT_PASS_LENGTH = "Passwords must be between 5 and 20 characters long"; + public static String CREATE_EMAIL_TOOLTIP = "Your email address is used to identify this account"; + public static String CREATE_PASSWORD_HINT = "Passwords must be between 5 and 20 letters and numbers"; + public static String CREATE_PASSWORD = "Password: "; + public static String BACK = "Back"; + public static String RETRY = "Retry"; + public static String TEXT_INTRO_3_START = "A fortunate few found more habitable planets and, around this handful of stars, civilization began to flourish once again."; + public static String VISIT_ACCOUNT_MANAGEMENT = "Visit the Account Management section on the main site to view."; + public static String DONT_TELL_PASSWORD = "You appear to be telling someone your password - please don't!"; + public static String CONNECTION_RESTORED = "Connection restored."; + public static String TEXT_STAT_ATTACKS_SUCCESSFUL = "Successful attacks"; + public static String ACCOUNT_CREATED_SUCCESSFULLY = "Account created successfully!"; + public static String TEXT_INSTRUCTIONS_GLOSSARY_1 = "<%glossary>FLEET - A collection of ships

<%glossary>SYSTEM - A star and its related planets. <%glossary>Systems are always controlled by a single player and only that player can have <%glossary>fleets stationed there. If another player's fleet enters the system, the two fleets engage in combat until one remains.

<%glossary>NEUTRAL - A <%glossary>system not under the control of any player. <%glossary>Neutral systems never attack and do not produce fleets.

<%glossary>WORMHOLE - <%glossary>Systems are connected by <%glossary>wormholes, which fleets use to move between systems. Fleets can jump along a single wormhole link per turn in <%glossary>neutral or hostile systems, but can chain jumps together in systems you control.

<%glossary>RESOURCE - There are four types of <%glossary>resource in <%highlight>Shattered Plans: <%resource0>, <%resource1>, <%resource2> and <%resource3>, and they are used to construct fleets and <%highlight>projects.

"; + public static String CREATE_USERNAME_AVAILABLE = "Name is available"; + public static String OK = "OK"; + public static String TAB_NAME_FLEET_INFO = "Fleet Info"; + public static String STATUS = "Status"; + public static String MU_X_CANNOT_JOIN_FULL = "<%0> cannot join; the game is full."; + public static String FLEET_HAS_RETREATED_TO = "1 fleet has retreated to <%0>"; + public static String TEXT_INSTRUCTIONS_MV_WORMHOLE = "Wormhole indicator"; + public static String PLEASE_CHANGE_PASSWORD = "If you are not, please change your password to something more obscure!"; + public static String REMOVE_FROM_IGNORE_FIRST = "Please remove <%0> from your ignore list first."; + public static String MU_ALL_PLAYERS_HAVE_LEFT = "All players have left <%0>'s game."; + public static String CREATE_ALERT_NAME_LENGTH = "Names should contain a maximum of 12 characters"; + public static String GAMEOPT_PLAYER_NEEDS_1_RATED_GAME = "<%0> must play 1 more rated game before playing with the current options."; + public static String WAITING_FOR_N_PLAYERS = "WAITING FOR <%0> PLAYERS."; + public static String GAME_OPTS_CHANGED = "Game options changed (<%0>)"; + public static String MU_X_ENTERED_GAME = "<%0> has entered a game."; + public static String PLEASE_WAIT = "Please wait..."; + public static String MU_X_JOINED_YOUR_GAME = "<%0> has joined your game."; + public static String MU_GAMELIST_AVG_RATING = "Average rating"; + public static String WAITING_FOR_GRAPHICS = "Waiting for graphics"; + public static String MU_X_ENTERED_OTHER_GAME = "<%0> has entered another game."; + public static String N_POINTS_1_PER_TURN = "<%0> points, 1 point per turn."; + public static String MU_X_LEFT_LOBBY = "<%0> has left the lobby."; + public static String MU_X_LOST_CON = "<%0> has lost connection."; + public static String MU_X_CANNOT_JOIN_IN_PROGRESS = "<%0> cannot join; the game has started."; + public static String MU_X_DECLINED_INVITE = "<%0> has declined the invitation."; + public static String MESSAGE_LOBBY = "Message lobby"; + public static String RULE_PILLAR_2 = "Security"; + public static String MU_X_WITHDREW_REQUEST = "<%0> has withdrawn the request to join."; + public static String MU_X_REMOVED = "<%0> has been removed."; + public static String TEXT_SHIPS = "Fleets"; + public static String FS_UNAVAILABLE = "Unfortunately your configuration doesn't support fullscreen mode."; + public static String COMM_IO_ERROR = "IO error - unable to communicate reliably with the data server. Please check any firewall/antivirus/filtering software."; + public static String TUTORIAL_EXIT = "To return to the menu, press <%key>'ESC' and select 'End Tutorial' from the menu."; + public static String MU_X_DROPPED_OUT = "<%0> has dropped out."; + public static String LOADING_EXTRA_DATA = "Loading extra data"; + public static String PASSWORD_IS_VALID = "Password is valid"; + public static String RULE_0_4 = "Scamming"; + public static String ACCEPT_PLAYER_INVITATION = "Accept invitation to <%0>'s game"; + public static String ONE_POINT_1_PER_TURN = "1 point, 1 point per turn."; + public static String MU_LOBBY_LOCATION = "Location"; + public static String MU_REQUEST_DECLINED = "Your request to join has been declined."; + public static String LOADING_GRAPHICS = "Loading graphics"; + public static String DISCARD = "Discard"; + public static String PENDING = "PENDING"; + public static String SHOWING_COMBAT_RESULTS = "Showing combat results."; + public static String TAB_NAME_PROJECTS = "Projects"; + public static String CHANGE_DISPLAY_NAME = "Change display name"; + public static String MULTICONST_FRIENDS = "Friends"; + public static String MU_LOBBY_NAME = "Name"; + public static String CHECKING = "Checking"; + public static String GAMEOPT_CANNOT_BE_COMBINED_2 = "This option cannot be combined with the current settings for: "; + public static String CREATING_YOUR_ACCOUNT = "Creating your account"; + public static String SEARCHING_FOR_OPPONENTS = "Searching for opponents"; + public static String START_SKIRMISH = "Start skirmish"; + public static String TUTORIAL = "Tutorial"; + public static String TEXT_INSTRUCTIONS_CLASSIC = "The <%highlight>Classic Ruleset adds some additional complexity to the game, and is only recommended for experienced players.

<%glossary>GARRISON - For each <%glossary>system, at least one fleet per <%glossary>wormhole link to a hostile or neutral territory needs to be garrisoned there, to maintain order. If the <%glossary>garrison level falls below this, you may lose control of the system. Systems at risk of collapse are overlaid with <%highlight>yellow or red crosshatching.

<%glossary>PRODUCTION - As with the normal rules, construction of one fleet requires one unit of each resource. If two regions that you control become disconnected, however, they are separated into distinct <%glossary>territories, and they produce fleets independently using the resources they contain. Fleets produced by a territory can only be placed within that territory."; + public static String INFO_RATED_GAME = "Here you can set up a rated game. If you win, your rating will go up. Ifyou lose, it will go down!

Please specify your preferences and click '<%0>'. Our system will then attempt to find suitable opponents in under a minute, depending on how busy the lobbyis.

This is an excellent way to get to know new people!"; + public static String TEXT_PEACE_3 = "All remaining colonies have agreed to a diplomatic settlement."; + public static String RULE_2_1 = "Breaking real-world laws"; + public static String FIND_OPPONENTS = "Find opponents"; + public static String MU_GAME_IS_FULL = "This game is full."; + public static String TEXT_JOIN = ", "; + public static String TEXT_JOIN_FINAL = " and "; + public static String SHOW_PLAYERS_IN_XS_GAME = "Show players in <%0>'s game"; + public static String TUTORIAL_BALANCED = "Our territory currently has balanced production, so you should seek to acquire all resources equally."; + public static String CLICK_TO_QUICKCHAT = "Click or press F10 to open Quick Chat"; + public static String RULE_0_1 = "Encouraging rule breaking"; + public static String TUTORIAL_SHORTFALL1 = "Our territory is currently short of <%0>, so to build more fleets we should concentrate on acquiring "; + public static String TUTORIAL_SHORTFALL_2B = "these resources."; + public static String TEXT_STAT_DESC_FLUIDITY = "Percentage of fleets moved each turn (average for game)."; + public static String TUTORIAL_CONTINUE_2 = "When ready, press 'ENTER' to continue."; + public static String TUTORIAL_SHORTFALL2A = "this resource."; + public static String TOOLTIP_TOTAL_FLEET_PRODUCTION = "Total fleets produced in this territory this turn."; + public static String MULTICONST_OPEN = "Open"; + public static String PACT_EXPIRES = "Expires in <%0> turns"; + public static String TEXT_INSTRUCTIONS_PROJECT_ENERGY = "<%PROJECT_ENERGY> - (<%Resource2>) A <%project_energy> causes devastating flares that destroy <%highlight>half of the fleet in the target <%glossary>system. If the target system has a <%project_metal>, the net will be destroyed instead. Additionally, any <%highlight>fleet moving out of the system is stopped. This project <%highlight>may not be used against an ally and you must control a system with a <%glossary>wormhole link to the target."; + public static String TEXT_INSTRUCTIONS_ANIMATION_PROJECT = "Project executed"; + public static String MU_GAME_HAS_STARTED = "This game has started."; + public static String TEXT_INSTRUCTIONS_PROJECT_METAL = "<%PROJECT_METAL> - (<%Resource0>) A <%project_metal> fortifies a system. The fleet strength of the <%glossary>system's garrison is treated as <%highlight>double when defending. This project may be used on any system you control."; + public static String TEXT_ANIMATING_MOVES = "Showing production, projects and fleet movements."; + public static String GAMEOPT_BADNUMPLAYERS = "You do not have a suitable number of players for the current options."; + public static String TEXT_ANIMATING_COLLAPSE = "Showing system collapses."; + public static String RULE_PILLAR_0 = "Honour"; + public static String TEXT_INSTRUCTIONS_SF_OUTGOING = "Outgoing fleet"; + public static String TEXT_ANIMATING_COMBAT = "Showing combat and damaged fleets retreating."; + public static String TEXT_INSTRUCTIONS_FLEETSIZE = "<%highlight>FLEET RESIZING - Once you have chosen a destination system for a move, you may <%highlight>increase or decrease the number of <%glossary>fleets you are sending there. This can be done via the <%highlight>tip of the arrow at the destination system. Simply <%key>click on the <%highlight>'+' button by the arrowhead to increase how many fleets you are sending, or on the <%highlight>'-' button to decrease it. Clicking the <%highlight>'X' button will cancel the order completely."; + public static String CREATE_SUGGESTIONS = "Suggested names: "; + public static String TOOLTIP_ANIM_CLICK_TO_PLAY = "Click to replay animation."; + public static String HINT_SELECT_SRC = "Select source star system to issue fleet orders."; + public static String TEXT_INSTRUCTIONS_STATS = "<%highlight>STATISTICS SCREEN - Pressing <%key>'SPACE' will display a page showing statistics from the active colonies. Pressing <%key>'SPACE' again will close it."; + public static String GAMEOPT_YOU_HAVENT_UNLOCKED = "You have not yet unlocked this option for use."; + public static String HINT_SELECT_DEST = "Select destination system in the same territory or connected by hyperspace link."; + public static String CREATE_DISPLAYNAME_TOOLTIP = "Enter the name you'd prefer. This is the name displayed to other players."; + public static String WARNING = "Warning"; + public static String MU_GAMEOPT_INVITE_X_TO_GAME = "Invite <%0> to this game"; + public static String HINT_DEFENSEGRID = "Select a friendly system to construct a defense grid, or right click to cancel this project."; + public static String CREATE_ALERT_PASSCHARS = "Passwords can only contain letters and numbers"; + public static String FS_ACCEPT_BEFORE_ACCEPT = "Click"; + public static String HINT_PLACEMENT = "Place fleets in territory <%0> (<%1> remaining)"; + public static String HINT_TERRAFORM = "Select a friendly system to commence terraforming, or right click to cancel this project."; + public static String HINT_FLARE = "Select a system adjacent to a friendly system to cause a destructive stellar flare, or right click to cancel this project."; + public static String ACHIEVEMENTS_OFFLINE = "The Achievements system is currently unavailable."; + public static String HINT_SELECT_GATE_SRC = "Select a friendly system to anchor one end of the Tannhäuser wormhole, or right click to cancel this project."; + public static String HINT_SELECT_GATE_DEST = "Select a system to anchor the other end of the Tannhäuser wormhole, or right click to cancel this project."; + public static String REPORT_X_FOR_ABUSE = "Report <%0> for abuse"; + public static String FRIEND_LIST_FULL = "Your friend list is full. Max of 100 for free users, and 200 for members."; + public static String TOOLTIP_PLACE_FLEETS = "Click to build fleets in this territory."; + public static String TOOLTIP_FLEETS_REMAINING = "<%0> fleets remaining."; + public static String SEND_PM = "Send private message"; + public static String TOOLTIP_ONE_FLEET_REMAINING = "1 fleet remaining."; + public static String MU_GAMEOPT_ACCEPT_X_INTO_GAME = "Accept <%0> into this game"; + public static String TEXT_PEACE_2 = "All colonies have agreed to a diplomatic settlement."; + public static String TOOLTIP_ALL_FLEETS_PLACED = "No more fleets available here."; + public static String TOOLTIP_ANIM_SPEED_IS_DOUBLE = "Animations speed is double. Click to halve."; + public static String TOOLTIP_ANIM_SPEED_IS_NORMAL = "Animations speed is normal. Click to double."; + public static String CREATE_EMAIL_CONFIRM = "Confirm Email:"; + public static String TOOLTIP_ANIM_CLICK_TO_STOP = "Click to stop animation."; + public static String CREATE_SELECT_ALTERNATIVE = "Use this alternative as your account name"; + public static String MP_REMATCH_NEW_GAME = "Set up new game"; + public static String TOOLTIP_ANIM_AUTO_PLAY_IS_OFF = "Animations do not play automatically. Click to enable."; + public static String RM_X_FROM_IGNORE = "Remove <%0> from ignore list"; + public static String SPECTATE_XS_GAME = "Spectate <%0>'s game"; + public static String TEXT_SHOW_CHAT = "C: Show Chat"; + public static String RA_SUGGEST_MUTE = "Suggest muting this player"; + public static String TOOLTIP_PRODUCTION_BUTTON_SHOW = "Click to show the Production window."; + public static String RETURN_TO_GAME = "Return to game"; + public static String GAMEOPT_CANNOT_BE_COMBINED_1 = "This option cannot be combined with the current '<%0>' setting."; + public static String YOUR_GAME = "Your game"; + public static String TEXT_INTRO_2_END = "Colonies were founded on a hundred worlds. Poorly equipped and without support, many failed. System after system was lost to the gathering night."; + public static String TOOLTIP_PROJECTS_BUTTON_SHOW = "Click to show the Projects window."; + public static String TEXT_INSTRUCTIONS_PROJECTS = "<%highlight>PROJECTS - After collecting <%highlight>5 units of research of any one type, a project becomes available. To use a project, <%key>click on the entry in the <%highlight>Projects window, then <%key>click on the target system(s). Each type of project has restrictions on its deployment, which will be explained when you've gathered enough resources to use it. When you use a project on a system, that system will be <%highlight>highlighted in the project's colour, and a <%highlight>coloured pip will appear above the system's defence strength."; + public static String TEXT_INTRO_1_END = "Unfortunately, the exotic physics involved were not fully understood. At some point in 2137, a catastrophic test flight destabilised Earth's sun."; + public static String TEXT_STAT_DESC_SHIPS_CONSTRUCTED = "Total number of fleets built."; + public static String MOUSE_OVER_AN_ICON = "Mouse over an icon for details"; + public static String TOOLTIP_DIPLOMACY_BUTTON_SHOW = "Click to show the Diplomacy window."; + public static String TOOLTIP_FLEET_INFO_BUTTON_SHOW = "Click to show the Fleet Info window."; + public static String TEXT_SKIRMISH = "Single-player Skirmish"; + public static String TUTORIAL_CONTINUE = "Press 'ENTER' to continue."; + public static String TOOLTIP_VICTORY_BUTTON_SHOW = "Click to show the Victory window."; + public static String OPTIONS_MENU_NOT_PAUSED = "Options Menu"; + public static String TOOLTIP_PRODUCTION_BUTTON_HIDE = "Click to hide the Production window."; + public static String SECRET_ACHIEVEMENT = "Secret achievement"; + public static String TOOLTIP_FLEET_INFO_BUTTON_HIDE = "Click to hide the Fleet Info window."; + public static String KICK = "Kick"; + public static String CANCEL_DRAW = "Cancel draw"; + public static String TOOLTIP_DIPLOMACY_BUTTON_HIDE = "Click to hide the Diplomacy window."; + public static String TOOLTIP_END_TURN = "Click to end turn."; + public static String CREATE_CREATE_AN_ACCOUNT = "Create a free Account"; + public static String MU_GAMEOPT_KICK_X_FROM_THIS_GAME = "Kick <%0> from this game"; + public static String TEXT_WAITING_FOR_PLAYER = "WAITING FOR 1 PLAYER."; + public static String TOOLTIP_PLACE_FLEET_STOP = "Click to stop building fleets in this territory."; + public static String PACT_ACCEPT = "Accept NAP"; + public static String CREATE_EMAIL_CONFIRM_TOOLTIP = "Type your email address again to make sure it's correct"; + public static String LOGIN_USERNAME_TOOLTIP = "The account name you use to access RuneScape and other Jagex.com games"; + public static String ASKING_TO_JOIN_XS_GAME = "Asking to join <%0>'s game..."; + public static String SERVICE_UNAVAILABLE = "Service unavailable"; + public static String YOU_ARE_INVITED_TO_XS_GAME = "You are invited to <%0>'s game."; + public static String TURN_NAME = "Year of <%0>"; + public static String RULE_PILLAR_1 = "Respect"; + public static String TEXT_DEFEAT = "DEFEAT!"; + public static String TEXT_INSTRUCTIONS_ICON_HOMEWORLD = "Colony homeworld"; + public static String MU_INVITE_PLAYERS = "Invite players"; + public static String LOGIN_USERNAME_EMAIL = "Login: "; + public static String TEXT_INSTRUCTIONS_ANIMATION_FLEETMOVE = "Fleets in motion"; + public static String TEXT_OVERVIEW = "Overview"; + public static String TEXT_PRODUCTION = "Production"; + public static String TEXT_SYSTEMS = "Systems"; + public static String ERROR_JS5CRC = "CRC mismatch - unable to get a valid download. Please check any firewall/antivirus/filtering software."; + public static String CREATE_ALERT_PASS_CONTAINS_NAME = "This password contains your Player Name, and would be easy to guess"; + public static String THIS_IS_RUNESCAPE_CLAN = "This is your RuneScape clan if you have one."; + public static String CREATE_DISPLAY_NAME = "Player Name: "; + public static String JUST_PLAY = "Just play"; + public static String FRIEND_LIST_DUPE = "<%0> is already on your friend list."; + public static String TEXT_NO_ACHIEVEMENT = "No Achievement"; + public static String TEXT_STAT_DESC_RESEARCH_WASTED = "Amount of wasted research data."; + public static String MESSAGE_GAME = "Message game"; + public static String TEXT_STAT_DESC_MAX_TOTAL_FLEET_SIZE = "Most fleets controlled at one time."; + public static String QUICK_CHAT_HELP = "Quick Chat Help"; + public static String RULE_1_4 = "Real-life threats"; + public static String UNABLE_TO_DELETE_IGNORE = "Unable to delete name - system busy"; + public static String TAB_NAME_PRODUCTION = "Production"; + public static String VICTORY_TARGET_POINTS = "Target: <%0> points"; + public static String RATING_NO_RATINGS = "No players"; + public static String GAMEOPT_PLAYER_NEEDS_RATED_GAMES = "<%0> must play <%1> more rated games before playing with the current options."; + public static String QUIT_TO_WEBSITE = "Quit to website"; + public static String TAB_NAME_DIPLOMACY = "Diplomacy"; + public static String TAB_NAME_VICTORY = "Victory"; + public static String TEXT_STAT_MAX_TOTAL_FLEET_SIZE = "Maximum total fleet size"; + public static String VICTORY_IN_X = "Victory in <%0>"; + public static String UNABLE_TO_DELETE_FRIEND = "Unable to delete friend - system busy"; + public static String TICKETING_X_UNREAD = "You have <%0> unread messages!"; + public static String TURN_FEWER_SHIPS = "<%0> fewer ships per turn"; + public static String MU_OPTIONS_ALLOW_SPECTATE = "Allow spectators?"; + public static String INVITE_DECLINE_XS_GAME = "Decline invitation to <%0>'s game"; + public static String TOOLTIP_WAIT_TREATY = "You have offered a Non-Agression Pact to <%0>."; + public static String TEXT_READY = "READY"; + public static String QUIT = "Quit"; + public static String TUTORIAL_LOST_MULTIPLE = "you lost <%0> fleets in the attack"; + public static String RATED_MEMBERS_ONLY = "Rated games are available to members only. To become a member, please visit the 'Account' section of the website."; + public static String TEXT_STAT_DESC_DEFENCES_SUCCESSFUL = "Battles won in friendly space."; + public static String TAB_NAME_UI_OPTIONS = "Display Options"; + public static String TEXT_INSTRUCTIONS_GAME_TYPE = "Shattered Plans has <%highlight>four different game types, each with a different <%glossary>victory condition.

<%highlight>CONQUEST - This is the simplest type of game: destroy all opponents to achieve victory. Any of the other game types can also be won in this way.

<%highlight>CAPTURE AND HOLD - The game has a fixed length of <%highlight>20 turns, and a fixed map layout. In the centre of the map is <%highlight>Sol and the damaged remains of Earth. At the end of each turn, the player who owns Sol earns <%highlight>1 point. At the end of the 20 turns, the surviving player with the highest score wins. <%glossary>Ties are broken in favour of the player who owns Sol. If none of the tied players own Sol, they draw and the other players lose.

<%highlight>POINTS - Players earn points each turn for the <%glossary>systems they own. <%glossary>Colony homeworlds are worth <%highlight>3 points each turn, <%glossary>neutral homeworlds are worth <%highlight>2 points, and other worlds are worth <%highlight>1 point each. The first player to reach the target number of points, which varies depending on map size, wins the game.

<%highlight>DERELICTS - Several <%glossary>derelict alien objects are scattered around the map. Capturing a derelict allows you to begin researching it, earning you points each turn. This research is expensive, however, and so owning a derelict <%highlight>reduces your income in each <%glossary>resource. The first player to reach the target of <%highlight>50 points wins.

"; + public static String MU_CHAT_PM_FRIENDS_ONLY = "Only show private chat from my friends and opponents"; + public static String PLAYERS_X_OF_Y = "Players: <%0>/<%1>"; + public static String CREATE_ALERT_YEAR_RANGE = "Please enter a year between <%0> and <%1>"; + public static String INVITE = "Invite"; + public static String TEXT_PERCENTAGE = "<%0>%"; + public static String TEXT_INSTRUCTIONS_ANIMATION = "<%highlight>Turn animations provide a brief overview of the events during the previous turn and play at the start of each turn by default. They can be disabled or replayed using the buttons at the <%highlight>bottom-right of the screen."; + public static String MU_GAMEOPT_REJECT_X_FROM_GAME = "Reject <%0> from this game"; + public static String TEXT_DECIMAL = "."; + public static String OFFER_DRAW = "Offer draw"; + public static String ERROR_JS5_CONNECT = "Unable to connect to the data server. Please check any firewall you are using."; + public static String YOU_CAN_ASK_TO_JOIN = "You can ask to join this game"; + public static String TEXT_STAT_DESC_ATTACKS_SUCCESSFUL = "Battles won in hostile space."; + public static String INVITING_X = "Inviting <%0>"; + public static String RA_INTRO = "To report a player, click on the most suitable option from the Rules of Conduct. Please do not abuse this form."; + public static String ACCEPT = "Accept"; + public static String MU_CHAT_FRIENDS = "Friends"; + public static String GAME_FULL = "Game full"; + public static String MU_CHAT_PM_SHOW_ALL = "Show all private chat"; + public static String MULTICONST_INVITE_ONLY = "Invite only"; + public static String TOOLTIP_PROJECT_COMPLETE = "Project is complete. Click to place."; + public static String LOADING = "Loading..."; + public static String TEXT_INSTRUCTIONS_ANIMATION_DAMAGED = "Fleets fleeing combat or collapsing system
(Damaged arrowhead)"; + public static String PLEASE_TRY_AGAIN = "Please try again in a few minutes."; + public static String RATING_DRAWN = "Drawn"; + public static String TURN_ORDINAL = "Turn: <%0>"; + public static String TEXT_INSTRUCTIONS_MV_ORDER = "Pending fleet order"; + public static String MP_X_HAS_LEFT = "<%0> has left."; + public static String TURN_POINTS = "<%0> points per turn"; + public static String PACT_OFFER = "Offer NAP"; + public static String RULE_2_2 = "Advertising websites"; + public static String WAITING_TO_START_HINT = "Hint: to start quickly, choose 'Don't mind' for as many options as you can!"; + public static String MU_CHAT_LOBBY_FRIENDS_ONLY = "Only show lobby chat from my friends"; + public static String MP_X_OFFERS_REMATCH = "<%0> is offering a rematch."; + public static String ACCEPT_DRAW = "Accept draw"; + public static String TUTORIAL_LOST_NONE = "you lost 0 fleets in the attack"; + public static String TEXT_RESIGNED = "Resigned"; + public static String XS_GAME = "<%0>'s game"; + public static String MU_CHAT_GAME_FRIENDS_ONLY = "Only show game chat from my friends"; + public static String IDLE_MESSAGE_20_MIN = "We closed the connection because the game was left unattended for 20 minutes. Please feel free to reconnect immediately if you are there."; + public static String YES = "Yes"; + public static String CREATE_PASSWORD_CONFIRM_TOOLTIP = "Type your password again to make sure it's correct"; + public static String CHAT_VIEW_SCROLLED_UP = "Chat view has been scrolled up. Scroll down to chat."; + public static String LOGIN_GAME_UPDATED = "This game has been updated! Please reload this page."; + public static String PRIVATE_CHAT_FRIEND_OFFLINE = "You cannot chat to <%0> because <%0> is offline in your friend list."; + public static String JOIN_WITHDRAW_REQUEST_XS_GAME = "Withdraw request to join <%0>'s game"; + public static String CREATE_OPT_IN_NEWS_TOOLTIP = "Updates will sent to the email address you've given"; + public static String TEXT_INSTRUCTIONS_SF_GARRISON = "System defensive strength"; + public static String TURN_OBJECTIVE = "Objective"; + public static String MU_CHAT_LOBBY = "Lobby"; + public static String MU_OPTIONS = "Game options"; + public static String TEXT_REMOVED_FROM_GAME = "Sorry, you were removed from the game you were in. This can happen if you are disconnected for too long or if the server is updated."; + public static String TEXT_STAT_DESC_AGGRESSIVENESS = "Percentage of fleets attacking each turn (average for game)."; + public static String LOGIN_NO_DISPLAY_NAME = "You need to choose a name before you can log in. This is the name that will be displayed to other players."; + public static String MU_REQUEST_WITHDRAWN = "You have withdrawn your request to join."; + public static String MU_CREATE_UNRATED = "Create unrated game"; + public static String TUTORIAL_LOST_SINGLE = "you lost 1 fleet in the attack"; + public static String OPEN_IN_POPUP_WINDOW = "Open in popup window"; + public static String LOGIN_JUST_PLAY_TOOLTIP = "Play the game without logging in just yet"; + public static String TURN_NAME_FIRST = "Year of Great Beginnings"; + public static String MP_X_HAS_RESIGNED = "<%0> has resigned."; + public static String UNRATED_GAME = "Unrated game"; + public static String DOB_ENTER_FOR_CHAT = "Please enter your date of birth to enable chat:"; + public static String TEXT_INSTRUCTIONS_ICON_TERRAFORMED = "Terraformed system"; + public static String RATED_GAME = "Rated game"; + public static String TEXT_INSTRUCTIONS_ANIMATION_CAPTURED = "System captured
(In colony colour)"; + public static String MP_X_HAS_RESIGNED_AND_LEFT = "<%0> has resigned and left."; + public static String CREATE_MORE_SUGGESTIONS = "More suggestions"; + public static String CREATE_AGE = "Age:"; + public static String RA_MUTE_THIS_PLAYER = "Mute this player for 48 hours"; + public static String WHO_CAN_JOIN = "Who can join"; + public static String TEXT_STAT_DESC_EFFICIENCY = "Resources used to construct vs total resources collected (average for game)."; + public static String FS_ACCEPT_COUNTDOWN_SING = "If you do nothing the game will revert to normal view in <%0> second."; + public static String TEXT_STAT_DESC_MAX_PRODUCTION = "Most fleets constructed in one turn."; + public static String MU_INVITE_WITHDRAWN = "The invitation has been withdrawn."; + public static String TURN_ONE_POINT = "1 point per turn"; + public static String RATED_GAME_TIPS_SETUP_SINGULAR = "Here you can set up a rated game. If you win, your rating will go up. Ifyou lose, it will go down!

Please specify your preferences and click '<%0>'. Our system will then attempt to find a suitable opponent in under a minute, depending on how busy the lobbyis.

This is an excellent way to get to know new people!"; + public static String GAMEOPT_PLAYER_NEEDS_RATING = "<%0> would need a rating of <%1> to play with the current options."; + public static String MP_REMATCH_NEW_GAME_UNRATED = "Set up new unrated game"; + public static String LOGIN_M3 = "Connection timed out. Please try using a different server."; + public static String CONT = "Continue"; + public static String WAITING_FOR_X_TO_START_GAME = "Waiting for <%0> to start the game..."; + public static String TEXT_STAT_SHIPS_DESTROYED = "Fleets destroyed"; + public static String JOIN_REQUESTS_MANY = "(<%0> players want to join)"; + public static String TOOLTIP_OFFER_TREATY = "Click to offer a Non-Agression Pact to <%0>."; + public static String MU_YOU_DECLINED_INVITE = "You have declined the invitation."; + public static String RETURN_TO_MAIN_MENU = "Return to Main Menu"; + public static String FRIEND_NOT_FOUND = "<%0> is not on your friend list."; + public static String PRIVATE_QUICK_CHAT_TO_X = "To <%0>: "; + public static String TEXT_VICTORY = "VICTORY!"; + public static String MU_GAME_CHAT_FRIENDS = "Show game chat from my friends"; + public static String FS_BUTTON_MEMBERS = "Members"; + public static String TOOLTIP_VICTORY_PANE_MANY_MANY = "<%0> points, <%1> points per turn."; + public static String YOU_CAN_SPECTATE = "You can spectate this game"; + public static String NO_OPTIONS_AVAILABLE = "No options available"; + public static String CONNECTION_LOST_RECONNECTING = "Connection lost - attempting to reconnect"; + public static String YOU_CAN_JOIN = "You can join this game"; + public static String PRESS_TAB_TO_CHAT = "Press TAB to chat or F10 to open Quick Chat."; + public static String CREATE_AGREE_TERMS = "By clicking Create, you agree to the <%0>Terms of Use<%1> and <%0>Privacy Policy<%1>."; + public static String TEXT_STAT_DEFENCES_SUCCESSFUL = "Successful defences"; + public static String RATED_GAME_TIPS = "Please wait while we search.
Games usually start within a minute, provided the server is busy enough.

The longer you are forced to wait, the earlier in the list of players you are likely to appear.

If the game doesn't start, click 'Cancel' and then try choosing 'Don't mind' for more options or switching to a busier lobby."; + public static String MU_GAMELIST_OPTIONS = "Options"; + public static String MP_YOU_OFFER_REMATCH = "You are offering a rematch."; + public static String LOGGING_IN = "Logging in..."; + public static String TEXT_STAT_SHIPS_CONSTRUCTED = "Fleets built"; + public static String MP_CANCEL_REMATCH_UNRATED = "Cancel unrated rematch"; + public static String CREATE_ALERT_PASS_CONTAINS_EMAIL = "This password contains your email address, and would be easy to guess"; + public static String GAMEOPT_PLEASE_SELECT_OPTION_1 = "Please select an option in the '<%0>' row."; + public static String FS_TIMEOUT = "Fullscreen mode was cancelled after a delay of 10 seconds. If you were unable to accept fullscreen mode during this time, there may be a problem with your configuration. You could try restarting your browser and trying again."; + public static String MU_OPTIONS_WHO_CAN_JOIN = "Who can join"; + public static String TEXT_STAT_EFFICIENCY = "Efficiency"; + public static String MP_X_WANTS_TO_DRAW = "<%0> wants to draw."; + public static String ENTER_IGNORE_ADD = "Enter name of player to add to list"; + public static String GO_BACK = "Go Back"; + public static String QUICK_CHAT_HELP_TITLE = "Shortcut Reference"; + public static String CREATE_U13_TERMS = "As you are under 13, we won't save your email address on our systems. Your email address will still be used to log in, but you won't recieve any emails from Jagex. For more information, please check the relevant parts of our <%0>Terms and Conditions<%1> and <%0>Privacy Policy<%1>."; + public static String SEND_PM_TO_X = "Send private message to <%0>"; + public static String OFFLINE = "Offline"; + public static String MP_ACCEPT_REMATCH = "Accept rematch"; + public static String TEXT_STAT_DESC_PROJECTS_USED = "Total number of projects deployed."; + public static String MU_CHAT_LOBBY_HIDE = "Hide lobby chat"; + public static String TEXT_HUMAN_PLAYERS = "Human Players"; + public static String TEXT_TOGGLE_STATS_2 = "(hiding this text)"; + public static String YOUR_RATING_IS_X = "Your rating is <%0>"; + public static String ACHIEVEMENTS_RATED_ONLY = "All achievements are available only in rated games."; + public static String MU_LOBBY_RATING = "Rating"; + public static String RA_INTRO_NO_NAME = "To report a player, right-click on their name and select the option to report abuse."; + public static String GAMEOPT_YOU_NEED_RATING = "You need a rating of <%1> to play with the current options."; + public static String YOU_ARE_ON_X_SERVER = "You are on <%0>"; + public static String MU_CHAT_INVISIBLE_AND_SILENT_MODE = "Hide private chat and appear offline to friends"; + public static String FIND_OPPONENT_SINGULAR = "Find opponent"; + public static String MU_CHAT_GAME_HIDE = "Hide game chat"; + public static String JOIN_REQUEST_XS_GAME = "Ask to join <%0>'s game"; + public static String JOIN_XS_GAME = "Join <%0>'s game"; + public static String MU_GAMEOPT_WITHDRAW_INVITE_TO_X = "Withdraw invitation to <%0> to join this game"; + public static String CREATE_ALERT_MISMATCH = "This entry doesn't match"; + public static String TEXT_INTRO_2_START = "Using a hastily converted fleet of experimental vessels, a small fraction of humanity managed to escape the scorched ruins of Earth."; + public static String GAMEOPT_PLAYER_HASNT_UNLOCKED = "<%0> has not yet unlocked this option for use."; + public static String MU_GAMELIST_ELAPSED_TIME = "Elapsed time"; + public static String CREATE_AGE_TOOLTIP = "Type your age in years"; + public static String TOOLTIP_PROJECTED_WINNER = "Projected winner."; + public static String JOIN_REQUESTS_ONE = "(1 player wants to join)"; + public static String CREATE_ALERT_PASS_CONTAINS_NAME_PARTIAL = "This password is part of your Player Name, and would be easy to guess"; + public static String TEXT_STAT_RESEARCH_WASTED = "Total excess research"; + public static String TEXT_TOTAL_PLAYERS = "Total number of players in game will not exceed 6."; + public static String GAMEOPT_UNSELECTED_OPTIONS = "The game options are not all set."; + public static String INVALID_PASS = "Invalid password."; + public static String CREATE_UNABLE = "Unfortunately we are unable to create an account for you at this time."; + public static String LOADING_MUSIC = "Loading music"; + public static String RATING_LOST = "Lost"; + public static String GAMEOPT_MIGHT_CHANGE = "<%0> might change the options - wait and see."; + public static String MU_CHAT_TIPS = "Tips"; + public static char KEYCHAR_THE_CHARACTER_UNDER_QUESTION_MARK = '/'; + public static String TUTORIAL_CAPTURE_ALL = "Capture all the systems on the map"; + public static String TEXT_STAT_ATTACKS_FAILED = "Failed attacks"; + public static String MU_CHAT_LOBBY_SHOW_ALL = "Show all lobby chat"; + public static String MU_CHAT_LOBBY_FRIENDS = "Show lobby chat from my friends"; + public static String MU_CHAT_GAME_SHOW_ALL = "Show all game chat"; + public static String RM_X_FROM_FRIENDS = "Remove <%0> from friend list"; + public static String ADD_X_TO_IGNORE = "Add <%0> to ignore list"; + public static String AUTO_RESPOND = "Auto-respond to <%0>"; + public static String QUICKCHAT_LOBBY = "Quick Chat lobby"; + public static String HIDE_PLAYERS_IN_XS_GAME = "Hide players in <%0>'s game"; + public static String IGNORE_NOT_FOUND = "<%0> is not on your ignore list."; + public static String TEXT_INSTRUCTIONS_0 = "Welcome to Shattered Plans. Before playing the game, we recommend you first select 'Tutorial' from the main menu.

<%highlight>BACKGROUND

You have been placed in command of the forces defending a colony of human survivors, following the disaster that rendered Earth uninhabitable.

It is your job to ensure your colony prospers and triumphs in the power struggle that has ensued after the colonies regained the power of spaceflight. To do so, you must <%highlight>capture resources to <%highlight>build your ships, maintain a flow of fleets to the front lines, and keep enough in reserve to <%highlight>maintain order in your central systems. You also have access to powerful research <%highlight>projects that may help you tip the balance."; + public static String TEXT_INTRO_1_START = "In the first half of the 22nd Century (Old Earth Reckoning) scientists in the Escher Programme began research into faster-than-light travel."; + public static String PRIVATE_QUICK_CHAT_FROM_X = "From <%0>: "; + public static String MP_ACCEPT_REMATCH_UNRATED = "Accept unrated rematch"; + public static String CREATE_PASSWORD_CONFIRM = "Confirm Password: "; + public static String REMOVE_FRIEND_FIRST = "Please remove <%0> from your friend list first."; + public static String RULE_0_0 = "Buying or selling an account"; + public static String FS_BUTTON_TRY_AGAIN = "Try again"; + public static String STATUS_PLAYING = "Playing"; + public static String MU_PLAY_RATED = "Play rated game"; + public static String TICKETING_ONE_UNREAD = "You have 1 unread message!"; + public static String MULTICONST_SIMILAR_RATING = "Similar rating"; + public static String MULTICONST_CLAN = "Clan"; + public static String MU_OPTIONS_DONT_MIND = "Don't mind"; + public static String NO = "No"; + public static String TOOLTIP_INCOME_LIMITING = "This resource is limiting your fleet production."; + public static String CREATE_INELIGIBLE = "Unfortunately you are not eligible to create an account."; + public static String IGNORE_LIST_FULL = "Your ignore list is full. Max of 100 hit."; + public static String GAMEOPT_INVITE_PLAYERS_OR_TRY_CHANGING_2 = "Invite more players, or alternatively try changing the following settings: "; + public static String TEXT_YOU_HAVE_BEEN_DEFEATED = "You have been defeated"; + public static String START_GAME = "Start Game"; + public static String FS_FOCUS = "Unfortunately there was a focus problem while setting fullscreen mode. You could try disabling any multiple monitor drivers or window enhancements, if you have any enabled."; + public static String ORB_POINTS = "Orb points: <%0>"; + public static String TEXT_STAT_SOLIDITY = "Solidity"; + public static String TOOLTIP_PROJECTS_BUTTON_HIDE = "Click to hide the Projects window."; + public static String MU_CHAT_OFF = "Off"; + public static String RATING_PLAYED = "Played"; + public static String PLAYERS_IN_GAME = "Players: "; + public static String REJECT = "Reject"; + public static String FS_NONMEMBER = "Fullscreen play is an option available to subscribing members only. For more details see the website."; + public static String RA_EXPLANATION = "A detailed explanation of each rule can be found through the link on our website.
(in the Help Section)"; + public static String CREATE_EMAIL_VALID = "Email is valid"; + public static String FS_ACCEPT_AFTER_ACCEPT = "to keep fullscreen or"; + public static String TAB_HIDE_CHAT_TEMPORARILY = "TAB - hide chat temporarily"; + public static String MU_LOBBY_FRIEND_ADD = "Add friend"; + public static String RATING_WON = "Won"; + public static String TEXT_ERROR = "ERROR!"; + public static String MP_YOU_OFFER_REMATCH_UNRATED = "You are offering an unrated rematch."; + public static String TEXT_INSTRUCTIONS_SF_RESOURCES = "Resource output"; + public static String ORB_POINTS_COLON = "Orb points: "; + public static String TEXT_INSTRUCTIONS_MV_TIME = "Time remaining"; + public static String CREATE_ALERT_NAME_LEADING_SPACE = "Names cannot start or end with space or underscore"; + public static String UNPACKING_MUSIC = "Unpacking music"; + public static String UNPACKING_GRAPHICS = "Unpacking graphics"; + public static String UNPACKING_SOUND_EFFECTS = "Unpacking sound effects"; + public static String WAITING_FOR_MUSIC = "Waiting for music"; + public static String WAITING_FOR_SOUND_EFFECTS = "Waiting for sound effects"; + public static String WAITING_FOR_FONTS = "Waiting for fonts"; + public static String MU_CHAT_IGNORE = "Ignore"; + public static String RULE_0_5 = "Exploiting a bug"; + public static String TEXT_MAP_SOL = "Game Type: Capture and Hold"; + public static String TEXT_MAP_POINTS = "Game Type: Points"; + public static String TEXT_MAP_DERELICTS = "Game Type: Derelicts"; + public static String TEXT_GARRISON_YES = "Rules: Classic"; + public static String END_TUTORIAL = "End Tutorial"; + public static String PAUSE_MENU = "Pause Menu"; + public static String FS_ACCEPT_AFTER_CANCEL = "to return to the normal view."; + public static String ESC_CANCEL_THIS_LINE = "ESC - cancel this line"; + public static String GAMEOPT_NEED_CHANGING_1 = "The '<%0>' setting needs to be changed."; + public static String TEXT_PEACE_SHORT = "PEACE!"; + public static String THIS_IS_RUNESCAPE_CLAN_NOT_OWNER = "This is <%0>'s RuneScape clan if they have one."; + public static String GAMEOPT_PLEASE_TRY_CHANGING = "Please try changing the following settings: "; + public static String LOGIN_CREATE_TOOLTIP = "Create your own free Jagex account"; + public static String LOG_IN = "Log in"; + public static String MU_OPTIONS_PLAYERS = "Players"; + public static String TUTORIAL_RETREATING_MULTIPLE = "<%1> fleets have retreated to <%0>"; + public static String TOOLTIP_ANIM_AUTO_PLAY_IS_ON = "Animations play automatically at the start of the turn. Click to disable."; + public static String CREATE_WELCOME = "Creating a Jagex account is simple and free. Your account will remember your progress, highscores and achievements in every game. You can also use it to play some of our multiplayer games - and Jagex's other games!

Please note - if you have a RuneScape account, you can click 'Go Back' and use your existing account to log in!"; + public static String TEXT_INSTRUCTIONS_MV_FRAME = "System HUD frame"; + public static String PRIVATE_CHAT_BLANK_AREA_EXPLANATION = "This private message is prefixed with \"To <%1>:\" on your screen.
On <%1>'s screen, it will be prefixed with \"From <%0>:\", which is
a different length and may leave less room for the message itself.

This shading covers the area which is not available on <%1>'s screen.
Provided your message fits to the left of the shaded area,
<%1> should be able to see it in full.

(Note: this may be inaccurate if <%1> is playing in a different
language from you.)"; + public static String PLAY_FREE_VERSION = "Play free version"; + public static String CREATE_EMAIL = "Email (Login):"; + public static String ENTER_FRIEND_DEL = "Enter name of friend to delete from list"; + public static String LOADING_FONTS = "Loading fonts"; + public static String GAMEOPT_TRY_CHANGING_1 = "Try changing the '<%0>' setting."; + public static String CREATE_PASSWORD_TOOLTIP = "Enter a password for this account. Try to pick a strong password that can't easily be guessed."; + public static String YOU_HAVE_BEEN_REMOVED_FROM_XS_GAME = "You have been removed from <%0>'s game."; + public static String PLEASE_LOG_IN = "Please log in to access this feature."; + public static String SEND_QC_TO_X = "Send private Quick Chat to <%0>"; + public static String LOADING_SOUND_EFFECTS = "Loading sound effects"; + public static String CREATE_DIPLAY_NAME_HINT = "Player names can be up to 12 letters, numbers and underscores"; + public static String MP_CANCEL_REMATCH = "Cancel rematch"; + public static String TEXT_NOT_AVAILABLE = "N/A"; + public static String MU_LOBBY_FRIEND_RM = "Remove friend"; + public static String HINT_CANCEL_PROJECT = "Right click to cancel the <%0> at <%1>"; + public static String TEXT_STAT_DESC_DEFENCES_FAILED = "Battles lost in friendly space."; + public static String RELOAD_GAME = "Reload game"; + public static String GAMEOPT_NO_VALID_COMBOS = "There are no valid types of game that match your preferences."; + public static String RULE_0_2 = "Staff impersonation"; + public static String TEXT_INTRO_4_END = "The fates of the children of Earth rest in your hands."; + public static String RULE_1_1 = "Solicitation"; + public static String SEARCHING_FOR_OPPONENT = "Searching for an opponent"; + public static String ADD_X_TO_FRIENDS = "Add <%0> to friend list"; + public static String RULE_1_0 = "Seriously offensive language"; + public static String TO_SERVER_LIST = "To server list"; + public static String MUSIC_COLON = "Music: "; + public static String TRACK_NAME_OLD = "Warring Worlds"; + public static String CLOSE = "Close"; + public static String TAB_NAME_MESSAGES = "Status Report"; + public static String TRACK_NAME_NEW = "Perpetual Motion"; + public static String MU_CHAT_GAME = "Game"; + public static String INVALID_NAME = "Invalid name"; + public static String RETURN_TO_LOBBY = "Return to lobby"; + public static String QUICKCHAT_GAME = "Quick Chat game"; + public static String FULLSCREEN = "Fullscreen"; + public static String CREATE_USERNAME_UNAVAILABLE = "That name is not available"; + public static String TEXT_INSTRUCTIONS_MV_READY = "End turn"; + public static String RANKINGS = "Rankings"; + public static String TEXT_INSTRUCTIONS_PROJECT_EXOTICS = "<%PROJECT_EXOTICS> - (<%Resource3>) The <%Project_Exotics> creates a <%highlight>temporary wormhole between two systems. This behaves as a normal <%glossary>wormhole for a three-turn duration. One end must be anchored in a friendly <%glossary>system, but the other end can be placed anywhere else on the map."; + public static String ERROR_JS5CONNECT_FULL = "Data server full or too many connections from your address. Please try again in a few minutes."; + public static String RESIGN = "Resign"; + public static String ENTER_MULTIPLAYER_LOBBY = "Enter multiplayer lobby"; + public static String ENTER_FRIEND_ADD = "Enter name of friend to add to list"; + public static String CONNECTING_TO_FRIEND_SERVER_TWO_LINE = "Connecting to
friend server..."; + public static String MU_CHAT_PM_FRIENDS = "Show private chat from my friends and opponents"; + public static String VICTORY_SOL_EMPTY = "Sol is unoccupied"; + public static String MENU = "Menu"; + public static String INSTRUCTIONS = "Instructions"; + public static String STATUS_SPECTATE = "Spectate"; + public static String MU_LOBBY_NAME_RM = "Remove name"; + public static String MU_GAMELIST_ALL_GAMES = "All games"; + public static String END_GAME = "End Game"; + public static String MU_CHAT_ON = "On"; + public static String TO_CUSTOMER_SUPPORT = "To Customer Support"; + public static String WATCH_INTRODUCTION = "Watch Introduction"; + public static String CREATE_OPT_IN_NEWS = "Please send me news and updates (I can unsubscribe at any time)"; + public static String SOUND_COLON = "Sound: "; + public static String YOU_CAN_NOT_SPECTATE = "No spectators"; + public static String TUTORIAL_CONTINUE_KEY = "'ENTER'"; + public static String MESSAGE_INCOMING_OFFERS = "You have incoming treaty offers."; + public static String TEXT_MAP_HEX = "Game Type: Conquest"; + public static String TEXT_GARRISON_NO = "Rules: Streamlined"; + public static String UNABLE_TO_ADD_IGNORE = "Unable to add name - system busy"; + public static String LOGIN_CREATE_ACCOUNT = "Log in / Create account"; + public static String STATUS_FULL = "Full"; + public static String TOOLTIP_PARTIALLY_COMPLETE = "Project is <%0>/5 complete."; + public static String ACHIEVEMENTS = "Achievements"; + public static String RATING_RATING = "Rating"; + public static String DAY = "Day"; + public static String MU_CHAT_PRIVATE = "Private"; + public static String TEXT_INSTRUCTIONS_GLOSSARY_2 = "<%glossary>PRODUCTION - Each <%glossary>system has a <%glossary>resource output. Most systems produce low levels of one or two types of resources and only a very few systems are rich in all types. Construction of a fleet requires one unit of each resource.

<%glossary>HOMEWORLD - A <%glossary>resource-rich system. A homeworld is either the starting system for one of the galaxy's colonies (indicated by <%highlight>three circles orbiting the system's current <%glossary>garrison figure) or a <%glossary>neutral homeworld (<%highlight>two circles).

<%glossary>NON-AGGRESSION PACT (NAP) - A temporary alliance between two colonies. After both parties agree to an alliance, they <%highlight>cannot attack each other for <%highlight>three turns. Once created, a <%glossary>NAP can <%highlight>neither be broken or extended.

<%glossary>GARRISON - Each <%glossary>system requires one fleet stationed in it, to maintain order. If you leave a system empty at the end of the turn, you will lose control of it. Systems expected to fall in this way are overlaid with <%highlight>red crosshatching. Systems that could fall due to attack have <%highlight>yellow crosshatching."; + public static String TOOLTIP_PROJECT_PENDING = "Project is complete and has been deployed. Click to cancel and deploy elsewhere."; + public static String IGNORE_LIST_DUPE = "<%0> is already on your ignore list."; + public static String X_WANTS_TO_JOIN = "<%0> wants to join"; + public static String YEAR = "Year"; + public static String UNABLE_TO_ADD_FRIEND = "Unable to add friend - system busy"; + public static String TEXT_INSTRUCTIONS_ANIMATION_COMBAT = "Combat in progress
(Red, Blue and Neutral involved)"; + public static String PRIVATE_CHAT_FRIEND_NOT_LISTED = "You cannot chat to <%0> because <%0> is not in your friend list."; + public static String TEXT_DEFEATED = "Defeated"; + public static String CREATE_ALERT_DOUBLE_SPACE = "Names cannot contain consecutive spaces"; + public static String TEXT_STAT_PROJECTS_USED = "Total projects used"; + public static String TOOLTIP_VICTORY_PANE_ONE_MANY = "1 point, <%0> points per turn."; + public static String VICTORY_SOL_OWNED = "Sol is owned by"; + public static String CREATE = "Create"; + public static String STATUS_JOIN = "Join"; + public static String TEXT_PEACE = "PEACE DECLARED!"; + public static String DEFAULT_PLAYER_NAME = "Player"; + public static String RULE_2_0 = "Asking for or providing contact information"; + public static String STATUS_PRIVATE = "Private"; + public static String PACT_AWAITING = "Awaiting response"; + public static String CANCEL = "Cancel"; + public static String WAITING_FOR_EXTRA_DATA = "Waiting for extra data"; + public static String WARNING_IF_YOU_QUIT = "Warning: if you quit, you will lose any game you are in the middle of!"; + public static String MU_GAMELIST_OWNER = "Owner"; + public static String PUBLIC_CHAT_UNAVAILABLE_RATED_GAME = "Public chat is unavailable while setting up a rated game."; + public static String TEXT_HIDE_CHAT = "C: Hide Chat"; + public static String CANNOT_ADD_YOURSELF = "You cannot add yourself!"; + public static String LOGIN_M2 = "Error connecting to server. Please try using a different server."; + public static String TEXT_PLAYER_HAS_WON = "<%0> HAS WON!"; + public static String MU_LOBBY_NAME_ADD = "Add name"; + public static String FS_ACCEPT_COUNTDOWN_PL = "If you do nothing the game will revert to normal view in <%0> seconds."; + public static String TEXT_STAT_DESC_ATTACKS_FAILED = "Battles lost in hostile space."; + public static String TEXT_INSTRUCTIONS_SF_INCOMING = "Incoming fleet"; + public static String ENTER_IGNORE_DEL = "Enter name of player to delete from list"; + public static String TUTORIAL_CONTINUE_3 = "Try this now, or press 'ENTER' to continue."; + public static String TOOLTIP_ACCEPT_TREATY = "Click to accept the Non-Agression Pact <%0> is offering."; + public static String TEXT_STAT_MAX_PRODUCTION = "Maximum total production"; + public static String TEXT_INSTRUCTIONS_PROJECT_BIOMASS = "<%PROJECT_BIOMASS> - (<%Resource1>) A >terraformed <%glossary>system always produces <%highlight>six resource units, which are not related to the production level of the system prior to <%project_biomass>. This project may be used on any system you control."; + public static String INVALID_USER_OR_PASS = "Invalid Login or Password

For accounts created after the 24th of November 2010, please use your email address to log in.

Otherwise please log in with your username."; + public static String TEXT_INTRO_4_START = "These are momentous times. Your colony is preparing to return to space once more. The now-perfected wormhole technology has revealed an array of possibilities and mighty starships shall once again seek destiny in the heavens."; + public static String REPORT_ABUSE = "Report abuse"; + public static String GAMEOPT_YOU_NEED_RATED_GAMES = "You must play <%1> more rated games before playing with the current options."; + public static String CREATE_ALERT_INVALID_EMAIL = "Please check if address is correct"; + public static String CREATE_ALERT_EMAIL_UNAVAILABLE = "Email address is unavailable"; + public static String CREATE_ALERT_INVALID_DATE = "Invalid date"; + public static String MONTH = "Month"; + public static String TEXT_INSTRUCTIONS_MOVEMENT = "<%highlight>FLEET MOVEMENT - To issue a fleet order, <%key>click on a <%glossary>system you control that has available fleets, then <%key>click on a destination system. Fleets can make <%highlight>one <%glossary>wormhole jump per turn through hostile territory, but can move an unlimited distance through your own systems. Fleets that are about to move are displayed as a <%highlight>curved arrow between the source and destination system."; + public static String PRESS_F10_TO_QUICK_CHAT = "Press F10 to open Quick Chat."; + public static String TEXT_INSTRUCTIONS_ICON_NEUTRAL = "Neutral homeworld"; + public static String TEXT_STAT_AVG_MOVE_SIZE = "Average fleet move size"; + public static String RULE_0_3 = "Macroing or use of bots"; + public static String YOU_CANNOT_JOIN_IN_PROGRESS = "You cannot join this game - it is in progress"; + public static String MP_X_OFFERS_REMATCH_UNRATED = "<%0> is offering an unrated rematch."; + public static String MU_GAMELIST_PLAYERS = "Players"; + public static String RUNESCAPE_CLAN = "RuneScape clan"; + public static String MP_YOU_RESIGNED = "You have resigned."; + public static String MP_YOU_OFFER_DRAW = "You are offering to draw."; + public static String MP_OFFER_REMATCH = "Offer rematch"; + public static String MP_OFFER_REMATCH_UNRATED = "Offer unrated rematch"; + public static String STATUS_CONCLUDED = "Concluded"; + public static String TEXT_INSTRUCTIONS_CLASSIC_STELLAR_BOMB = "

<%PROJECT_ENERGY> - In the Classic rules, a <%project_energy> does not destroy a <%project_metal> in the target system. Instead, the bomb will destroy half the fleets in the system but leave the net in place. It will also prevent fleets leaving the system as normal."; + public static String MU_ENTERED_OTHER_GAME = "You have entered another game."; + public static String DOB_CHAT_DISABLED = "Chat is currently disabled."; + public static String RULE_1_3 = "Offensive account name"; + public static String RULE_1_2 = "Disruptive behaviour"; + public static String GAMEOPT_INVITE_PLAYERS_OR_TRY_CHANGING_1 = "Invite more players, or alternatively try changing the '<%0>' setting."; + public static String GAMEOPT_PLEASE_SELECT_OPTION_2 = "Please select options in the following rows: "; + public static String TEXT_INSTRUCTIONS_PLACEMENT = "<%highlight>FLEET PLACEMENT - To place fleets, <%key>click on your Production panel (at the top of the <%highlight>Production window), then <%key>click on a <%glossary>system you control."; + public static String TEXT_TOGGLE_STATS = "Press 'SPACE' to toggle game statistics"; + public static String TEXT_INSTRUCTIONS_END_TURN = "<%highlight>ENDING TURNS - <%key>Clicking on the Ready button (a <%highlight>tick within a circle) at the top-right of the screen marks your move as complete. Once all players have completed their moves, <%highlight>all orders will be executed and a new turn will begin. Making any adjustments to your orders will clear your ready status, and you will need to press the button again when you are finished."; + public static String TEXT_STAT_DEFENCES_FAILED = "Failed defences"; + public static String TEXT_STAT_FLUIDITY = "Fluidity"; + public static String TEXT_STAT_AGGRESSIVENESS = "Aggressiveness"; + public static String TEXT_STAT_DESC_SHIPS_DESTROYED = "Opposing fleets destroyed."; + public static String TEXT_STAT_DESC_SHIPS_LOST = "Total fleets lost."; + public static String TEXT_STAT_DESC_AVG_MOVE_SIZE = "Average number of fleets committed to each operation."; + public static String TEXT_STAT_DESC_SOLIDITY = "Percentage of battles won in friendly space."; + public static String FS_BUTTON_CANCEL = "Cancel"; + public static String FS_BUTTON_ACCEPT = "Accept"; + public static String CREATE_TO_USE = "Create a free account to start using this feature"; + public static String TEXT_INSTRUCTIONS_HOTKEYS = "<%highlight>HOT KEYS - For placement, fleet moves and fleet strength adjustment, <%key>'SHIFT' will make changes in units of <%highlight>one fleet, <%key>'ALT' will use units of <%highlight>5 fleets, and <%key>'CTRL' will use <%highlight>all available fleets."; + public static String TEXT_INSTRUCTIONS_SF_NAME = "System name"; + public static String TEXT_ENEMY_PRODUCTION = "Enemy Production"; + public static String TEXT_SKIP_INTRO = "Skip Intro"; + public static String TEXT_ESC_TO_EXIT = "Press 'ESC' to exit the game"; + public static String FS_BUTTON_CLOSE = "Close"; + public static String RA_TITLE = "Report abuse"; + + public static void loadCommon(final ResourceLoader loader) { + loadString(loader, "loginm3", str -> LOGIN_M3 = str); + loadString(loader, "loginm2", str -> LOGIN_M2 = str); + loadString(loader, "idlemessage20min", str -> IDLE_MESSAGE_20_MIN = str); + loadString(loader, "error_js5crc", str -> ERROR_JS5CRC = str); + loadString(loader, "error_js5io", str -> COMM_IO_ERROR = str); + loadString(loader, "error_js5connect_full", str -> ERROR_JS5CONNECT_FULL = str); + loadString(loader, "error_js5connect", str -> ERROR_JS5_CONNECT = str); + loadString(loader, "login_gameupdated", str -> LOGIN_GAME_UPDATED = str); + loadString(loader, "create_unable", str -> CREATE_UNABLE = str); + loadString(loader, "create_ineligible", str -> CREATE_INELIGIBLE = str); + loadString(loader, "ticketing_oneunread", str -> TICKETING_ONE_UNREAD = str); + loadString(loader, "ticketing_xunread", str -> TICKETING_X_UNREAD = str); + loadString(loader, "ticketing_gotowebsite", str -> VISIT_ACCOUNT_MANAGEMENT = str); + loadString(loader, "mu_chat_on", str -> MU_CHAT_ON = str); + loadString(loader, "mu_chat_friends", str -> MU_CHAT_FRIENDS = str); + loadString(loader, "mu_chat_off", str -> MU_CHAT_OFF = str); + loadString(loader, "mu_chat_lobby", str -> MU_CHAT_LOBBY = str); + loadString(loader, "mu_chat_ignore", str -> MU_CHAT_IGNORE = str); + loadString(loader, "mu_chat_tips", str -> MU_CHAT_TIPS = str); + loadString(loader, "mu_chat_game", str -> MU_CHAT_GAME = str); + loadString(loader, "mu_chat_private", str -> MU_CHAT_PRIVATE = str); + loadString(loader, "mu_x_entered_game", str -> MU_X_ENTERED_GAME = str); + loadString(loader, "mu_x_joined_your_game", str -> MU_X_JOINED_YOUR_GAME = str); + loadString(loader, "mu_x_entered_other_game", str -> MU_X_ENTERED_OTHER_GAME = str); + loadString(loader, "mu_x_left_lobby", str -> MU_X_LEFT_LOBBY = str); + loadString(loader, "mu_x_lost_con", str -> MU_X_LOST_CON = str); + loadString(loader, "mu_x_cannot_join_full", str -> MU_X_CANNOT_JOIN_FULL = str); + loadString(loader, "mu_x_cannot_join_inprogress", str -> MU_X_CANNOT_JOIN_IN_PROGRESS = str); + loadString(loader, "mu_x_declined_invite", str -> MU_X_DECLINED_INVITE = str); + loadString(loader, "mu_x_withdrew_request", str -> MU_X_WITHDREW_REQUEST = str); + loadString(loader, "mu_x_removed", str -> MU_X_REMOVED = str); + loadString(loader, "mu_x_dropped_out", str -> MU_X_DROPPED_OUT = str); + loadString(loader, "mu_entered_other_game", str -> MU_ENTERED_OTHER_GAME = str); + loadString(loader, "mu_game_is_full", str -> MU_GAME_IS_FULL = str); + loadString(loader, "mu_game_has_started", str -> MU_GAME_HAS_STARTED = str); + loadString(loader, "mu_you_declined_invite", str -> MU_YOU_DECLINED_INVITE = str); + loadString(loader, "mu_invite_withdrawn", str -> MU_INVITE_WITHDRAWN = str); + loadString(loader, "mu_request_declined", str -> MU_REQUEST_DECLINED = str); + loadString(loader, "mu_request_withdrawn", str -> MU_REQUEST_WITHDRAWN = str); + loadString(loader, "mu_all_players_have_left", str -> MU_ALL_PLAYERS_HAVE_LEFT = str); + loadString(loader, "mu_lobby_name", str -> MU_LOBBY_NAME = str); + loadString(loader, "mu_lobby_rating", str -> MU_LOBBY_RATING = str); + loadString(loader, "mu_lobby_friend_add", str -> MU_LOBBY_FRIEND_ADD = str); + loadString(loader, "mu_lobby_friend_rm", str -> MU_LOBBY_FRIEND_RM = str); + loadString(loader, "mu_lobby_name_add", str -> MU_LOBBY_NAME_ADD = str); + loadString(loader, "mu_lobby_name_rm", str -> MU_LOBBY_NAME_RM = str); + loadString(loader, "mu_lobby_location", str -> MU_LOBBY_LOCATION = str); + loadString(loader, "mu_gamelist_all_games", str -> MU_GAMELIST_ALL_GAMES = str); + loadString(loader, "mu_gamelist_status", str -> STATUS = str); + loadString(loader, "mu_gamelist_owner", str -> MU_GAMELIST_OWNER = str); + loadString(loader, "mu_gamelist_players", str -> MU_GAMELIST_PLAYERS = str); + loadString(loader, "mu_gamelist_avg_rating", str -> MU_GAMELIST_AVG_RATING = str); + loadString(loader, "mu_gamelist_options", str -> MU_GAMELIST_OPTIONS = str); + loadString(loader, "mu_gamelist_elapsed_time", str -> MU_GAMELIST_ELAPSED_TIME = str); + loadString(loader, "mu_play_rated", str -> MU_PLAY_RATED = str); + loadString(loader, "mu_create_unrated", str -> MU_CREATE_UNRATED = str); + loadString(loader, "mu_options", str -> MU_OPTIONS = str); + loadString(loader, "mu_options_whocanjoin", str -> MU_OPTIONS_WHO_CAN_JOIN = str); + loadString(loader, "mu_options_players", str -> MU_OPTIONS_PLAYERS = str); + loadString(loader, "mu_options_dontmind", str -> MU_OPTIONS_DONT_MIND = str); + loadString(loader, "mu_options_allow_spectate", str -> MU_OPTIONS_ALLOW_SPECTATE = str); + loadString(loader, "yes", str -> YES = str); + loadString(loader, "no", str -> NO = str); + loadString(loader, "mu_invite_players", str -> MU_INVITE_PLAYERS = str); + loadString(loader, "close", str -> CLOSE = str); + loadString(loader, "add_x_to_friends", str -> ADD_X_TO_FRIENDS = str); + loadString(loader, "add_x_to_ignore", str -> ADD_X_TO_IGNORE = str); + loadString(loader, "rm_x_from_friends", str -> RM_X_FROM_FRIENDS = str); + loadString(loader, "rm_x_from_ignore", str -> RM_X_FROM_IGNORE = str); + loadString(loader, "send_pm_to_x", str -> SEND_PM_TO_X = str); + loadString(loader, "send_qc_to_x", str -> SEND_QC_TO_X = str); + loadString(loader, "send_pm", str -> SEND_PM = str); + loadString(loader, "invite_accept_xs_game", str -> ACCEPT_PLAYER_INVITATION = str); + loadString(loader, "invite_decline_xs_game", str -> INVITE_DECLINE_XS_GAME = str); + loadString(loader, "join_xs_game", str -> JOIN_XS_GAME = str); + loadString(loader, "join_request_xs_game", str -> JOIN_REQUEST_XS_GAME = str); + loadString(loader, "join_withdraw_request_xs_game", str -> JOIN_WITHDRAW_REQUEST_XS_GAME = str); + loadString(loader, "mu_gameopt_kick_x_from_this_game", str -> MU_GAMEOPT_KICK_X_FROM_THIS_GAME = str); + loadString(loader, "mu_gameopt_withdraw_invite_to_x", str -> MU_GAMEOPT_WITHDRAW_INVITE_TO_X = str); + loadString(loader, "mu_gameopt_accept_x_into_game", str -> MU_GAMEOPT_ACCEPT_X_INTO_GAME = str); + loadString(loader, "mu_gameopt_reject_x_from_game", str -> MU_GAMEOPT_REJECT_X_FROM_GAME = str); + loadString(loader, "mu_gameopt_invite_x_to_game", str -> MU_GAMEOPT_INVITE_X_TO_GAME = str); + loadString(loader, "report_x_for_abuse", str -> REPORT_X_FOR_ABUSE = str); + loadString(loader, "unable_to_send_message_password_a", str -> DONT_TELL_PASSWORD = str); + loadString(loader, "unable_to_send_message_password_b", str -> PLEASE_CHANGE_PASSWORD = str); + loadString(loader, "mu_chat_lobby_show_all", str -> MU_CHAT_LOBBY_SHOW_ALL = str); + loadString(loader, "mu_chat_lobby_friends_only", str -> MU_CHAT_LOBBY_FRIENDS_ONLY = str); + loadString(loader, "mu_chat_lobby_friends", str -> MU_CHAT_LOBBY_FRIENDS = str); + loadString(loader, "mu_chat_lobby_hide", str -> MU_CHAT_LOBBY_HIDE = str); + loadString(loader, "mu_chat_game_show_all", str -> MU_CHAT_GAME_SHOW_ALL = str); + loadString(loader, "mu_chat_game_friends_only", str -> MU_CHAT_GAME_FRIENDS_ONLY = str); + loadString(loader, "mu_chat_game_friends", str -> MU_GAME_CHAT_FRIENDS = str); + loadString(loader, "mu_chat_game_hide", str -> MU_CHAT_GAME_HIDE = str); + loadString(loader, "mu_chat_pm_show_all", str -> MU_CHAT_PM_SHOW_ALL = str); + loadString(loader, "mu_chat_pm_friends_only", str -> MU_CHAT_PM_FRIENDS_ONLY = str); + loadString(loader, "mu_chat_pm_friends", str -> MU_CHAT_PM_FRIENDS = str); + loadString(loader, "mu_chat_invisible_and_silent_mode", str -> MU_CHAT_INVISIBLE_AND_SILENT_MODE = str); + loadString(loader, "you_have_been_removed_from_xs_game", str -> YOU_HAVE_BEEN_REMOVED_FROM_XS_GAME = str); + loadString(loader, "your_rating_is_x", str -> YOUR_RATING_IS_X = str); + loadString(loader, "you_are_on_x_server", str -> YOU_ARE_ON_X_SERVER = str); + loadString(loader, "rated_game", str -> RATED_GAME = str); + loadString(loader, "unrated_game", str -> UNRATED_GAME = str); + loadString(loader, "rated_game_tips", str -> RATED_GAME_TIPS = str); + loadString(loader, "searching_for_opponent_singular", str -> SEARCHING_FOR_OPPONENT = str); + loadString(loader, "searching_for_opponents_plural", str -> SEARCHING_FOR_OPPONENTS = str); + loadString(loader, "find_opponent_singular", str -> FIND_OPPONENT_SINGULAR = str); + loadString(loader, "find_opponents_plural", str -> FIND_OPPONENTS = str); + loadString(loader, "rated_game_tips_setup_singular", str -> RATED_GAME_TIPS_SETUP_SINGULAR = str); + loadString(loader, "rated_game_tips_setup_plural", str -> INFO_RATED_GAME = str); + loadString(loader, "waiting_to_start_hint", str -> WAITING_TO_START_HINT = str); + loadString(loader, "your_game", str -> YOUR_GAME = str); + loadString(loader, "game_full", str -> GAME_FULL = str); + loadString(loader, "join_requests_one", str -> JOIN_REQUESTS_ONE = str); + loadString(loader, "join_requests_many", str -> JOIN_REQUESTS_MANY = str); + loadString(loader, "xs_game", str -> XS_GAME = str); + loadString(loader, "waiting_for_x_to_start_game", str -> WAITING_FOR_X_TO_START_GAME = str); + loadString(loader, "game_options_changed", str -> GAME_OPTS_CHANGED = str); + loadString(loader, "players_x_of_y", str -> PLAYERS_X_OF_Y = str); + loadString(loader, "message_lobby", str -> MESSAGE_LOBBY = str); + loadString(loader, "quickchat_lobby", str -> QUICKCHAT_LOBBY = str); + loadString(loader, "message_game", str -> MESSAGE_GAME = str); + loadString(loader, "quickchat_game", str -> QUICKCHAT_GAME = str); + loadString(loader, "kick", str -> KICK = str); + loadString(loader, "inviting_x", str -> INVITING_X = str); + loadString(loader, "x_wants_to_join", str -> X_WANTS_TO_JOIN = str); + loadString(loader, "accept", str -> ACCEPT = str); + loadString(loader, "reject", str -> REJECT = str); + loadString(loader, "invite", str -> INVITE = str); + loadString(loader, "status_concluded", str -> STATUS_CONCLUDED = str); + loadString(loader, "status_spectate", str -> STATUS_SPECTATE = str); + loadString(loader, "status_playing", str -> STATUS_PLAYING = str); + loadString(loader, "status_join", str -> STATUS_JOIN = str); + loadString(loader, "status_private", str -> STATUS_PRIVATE = str); + loadString(loader, "status_full", str -> STATUS_FULL = str); + loadString(loader, "players_in_game", str -> PLAYERS_IN_GAME = str); + loadString(loader, "you_are_invited_to_xs_game", str -> YOU_ARE_INVITED_TO_XS_GAME = str); + loadString(loader, "asking_to_join_xs_game", str -> ASKING_TO_JOIN_XS_GAME = str); + loadString(loader, "who_can_join", str -> WHO_CAN_JOIN = str); + loadString(loader, "you_can_join", str -> YOU_CAN_JOIN = str); + loadString(loader, "you_can_ask_to_join", str -> YOU_CAN_ASK_TO_JOIN = str); + loadString(loader, "you_cannot_join_in_progress", str -> YOU_CANNOT_JOIN_IN_PROGRESS = str); + loadString(loader, "you_can_spectate", str -> YOU_CAN_SPECTATE = str); + loadString(loader, "you_can_not_spectate", str -> YOU_CAN_NOT_SPECTATE = str); + loadString(loader, "spectate_xs_game", str -> SPECTATE_XS_GAME = str); + loadString(loader, "hide_players_in_xs_game", str -> HIDE_PLAYERS_IN_XS_GAME = str); + loadString(loader, "show_players_in_xs_game", str -> SHOW_PLAYERS_IN_XS_GAME = str); + loadString(loader, "connecting_to_friend_server_twoline", str -> CONNECTING_TO_FRIEND_SERVER_TWO_LINE = str); + loadString(loader, "loading", str -> LOADING = str); + loadString(loader, "offline", str -> OFFLINE = str); + loadString(loader, "multiconst_invite_only", str -> MULTICONST_INVITE_ONLY = str); + loadString(loader, "multiconst_clan", str -> MULTICONST_CLAN = str); + loadString(loader, "multiconst_friends", str -> MULTICONST_FRIENDS = str); + loadString(loader, "multiconst_similar_rating", str -> MULTICONST_SIMILAR_RATING = str); + loadString(loader, "multiconst_open", str -> MULTICONST_OPEN = str); + loadString(loader, "no_options_available", str -> NO_OPTIONS_AVAILABLE = str); + loadString(loader, "reportabuse", str -> REPORT_ABUSE = str); + loadString(loader, "presstabtochat", str -> PRESS_TAB_TO_CHAT = str); + loadString(loader, "pressf10toquickchat", str -> PRESS_F10_TO_QUICK_CHAT = str); + loadString(loader, "dob_chatdisabled", str -> DOB_CHAT_DISABLED = str); + loadString(loader, "dob_enterforchat", str -> DOB_ENTER_FOR_CHAT = str); + loadString(loader, "tab_hidechattemporarily", str -> TAB_HIDE_CHAT_TEMPORARILY = str); + loadString(loader, "esc_cancelprivatemessage", str -> ReportAbuseDialog._Kb = str); + loadString(loader, "esc_cancelthisline", str -> ESC_CANCEL_THIS_LINE = str); + loadString(loader, "privatequickchat_from_x", str -> PRIVATE_QUICK_CHAT_FROM_X = str); + loadString(loader, "privatequickchat_to_x", str -> PRIVATE_QUICK_CHAT_TO_X = str); + loadString(loader, "privatechat_blankarea_explanation", str -> PRIVATE_CHAT_BLANK_AREA_EXPLANATION = str); + loadString(loader, "publicchat_unavailable_ratedgame", str -> PUBLIC_CHAT_UNAVAILABLE_RATED_GAME = str); + loadString(loader, "privatechat_friend_offline", str -> PRIVATE_CHAT_FRIEND_OFFLINE = str); + loadString(loader, "privatechat_friend_notlisted", str -> PRIVATE_CHAT_FRIEND_NOT_LISTED = str); + loadString(loader, "chatviewscrolledup", str -> CHAT_VIEW_SCROLLED_UP = str); + loadString(loader, "thisisrunescapeclan", str -> THIS_IS_RUNESCAPE_CLAN = str); + loadString(loader, "thisisrunescapeclan_notowner", str -> THIS_IS_RUNESCAPE_CLAN_NOT_OWNER = str); + loadString(loader, "runescapeclan", str -> RUNESCAPE_CLAN = str); + loadString(loader, "gameopt_cannotbecombined1", str -> GAMEOPT_CANNOT_BE_COMBINED_1 = str); + loadString(loader, "gameopt_cannotbecombined2", str -> GAMEOPT_CANNOT_BE_COMBINED_2 = str); + loadString(loader, "gameopt_playerneedsrating", str -> GAMEOPT_PLAYER_NEEDS_RATING = str); + loadString(loader, "gameopt_youneedrating", str -> GAMEOPT_YOU_NEED_RATING = str); + loadString(loader, "gameopt_playerneedsratedgames", str -> GAMEOPT_PLAYER_NEEDS_RATED_GAMES = str); + loadString(loader, "gameopt_youneedratedgames", str -> GAMEOPT_YOU_NEED_RATED_GAMES = str); + loadString(loader, "gameopt_playerneeds1ratedgame", str -> GAMEOPT_PLAYER_NEEDS_1_RATED_GAME = str); + loadString(loader, "gameopt_playerhasntunlocked", str -> GAMEOPT_PLAYER_HASNT_UNLOCKED = str); + loadString(loader, "gameopt_youhaventunlocked", str -> GAMEOPT_YOU_HAVENT_UNLOCKED = str); + loadString(loader, "gameopt_trychanging1", str -> GAMEOPT_TRY_CHANGING_1 = str); + loadString(loader, "gameopt_needchanging1", str -> GAMEOPT_NEED_CHANGING_1 = str); + loadString(loader, "gameopt_mightchange", str -> GAMEOPT_MIGHT_CHANGE = str); + loadString(loader, "gameopt_unselectedoptions", str -> GAMEOPT_UNSELECTED_OPTIONS = str); + loadString(loader, "gameopt_pleaseselectoption1", str -> GAMEOPT_PLEASE_SELECT_OPTION_1 = str); + loadString(loader, "gameopt_pleaseselectoption2", str -> GAMEOPT_PLEASE_SELECT_OPTION_2 = str); + loadString(loader, "gameopt_badnumplayers", str -> GAMEOPT_BADNUMPLAYERS = str); + loadString(loader, "gameopt_inviteplayers_or_trychanging1", str -> GAMEOPT_INVITE_PLAYERS_OR_TRY_CHANGING_1 = str); + loadString(loader, "gameopt_inviteplayers_or_trychanging2", str -> GAMEOPT_INVITE_PLAYERS_OR_TRY_CHANGING_2 = str); + loadString(loader, "gameopt_novalidcombos", str -> GAMEOPT_NO_VALID_COMBOS = str); + loadString(loader, "gameopt_pleasetrychanging", str -> GAMEOPT_PLEASE_TRY_CHANGING = str); + loadString(loader, "ra_title", str -> RA_TITLE = str); + loadString(loader, "ra_mutethisplayer", str -> RA_MUTE_THIS_PLAYER = str); + loadString(loader, "ra_suggestmute", str -> RA_SUGGEST_MUTE = str); + loadString(loader, "ra_intro", str -> RA_INTRO = str); + loadString(loader, "ra_intro_no_name", str -> RA_INTRO_NO_NAME = str); + loadString(loader, "ra_explanation", str -> RA_EXPLANATION = str); + loadString(loader, "rule_pillar_0", str -> RULE_PILLAR_0 = str); + loadString(loader, "rule_0_0", str -> RULE_0_0 = str); + loadString(loader, "rule_0_1", str -> RULE_0_1 = str); + loadString(loader, "rule_0_2", str -> RULE_0_2 = str); + loadString(loader, "rule_0_3", str -> RULE_0_3 = str); + loadString(loader, "rule_0_4", str -> RULE_0_4 = str); + loadString(loader, "rule_0_5", str -> RULE_0_5 = str); + loadString(loader, "rule_pillar_1", str -> RULE_PILLAR_1 = str); + loadString(loader, "rule_1_0", str -> RULE_1_0 = str); + loadString(loader, "rule_1_1", str -> RULE_1_1 = str); + loadString(loader, "rule_1_2", str -> RULE_1_2 = str); + loadString(loader, "rule_1_3", str -> RULE_1_3 = str); + loadString(loader, "rule_1_4", str -> RULE_1_4 = str); + loadString(loader, "rule_pillar_2", str -> RULE_PILLAR_2 = str); + loadString(loader, "rule_2_0", str -> RULE_2_0 = str); + loadString(loader, "rule_2_1", str -> RULE_2_1 = str); + loadString(loader, "rule_2_2", str -> RULE_2_2 = str); + loadString(loader, "cancel", str -> CANCEL = str); + loadString(loader, "pleaselogin", str -> PLEASE_LOG_IN = str); + loadString(loader, "invaliduserorpass", str -> INVALID_USER_OR_PASS = str); + loadString(loader, "pleasetryagain", str -> PLEASE_TRY_AGAIN = str); + loadString(loader, "playfreeversion", str -> PLAY_FREE_VERSION = str); + loadString(loader, "reloadgame", str -> RELOAD_GAME = str); + loadString(loader, "toserverlist", str -> TO_SERVER_LIST = str); + loadString(loader, "tocustomersupport", str -> TO_CUSTOMER_SUPPORT = str); + loadString(loader, "changedisplayname", str -> CHANGE_DISPLAY_NAME = str); + loadString(loader, "justplay", str -> JUST_PLAY = str); + loadString(loader, "login", str -> LOG_IN = str); + loadString(loader, "goback", str -> GO_BACK = str); + loadString(loader, "logging_in", str -> LOGGING_IN = str); + loadString(loader, "connectionlost_reconnecting", str -> CONNECTION_LOST_RECONNECTING = str); + loadString(loader, "invalidpass", str -> INVALID_PASS = str); + loadString(loader, "retry", str -> RETRY = str); + loadString(loader, "back", str -> BACK = str); + loadString(loader, "quittowebsite", str -> QUIT_TO_WEBSITE = str); + loadString(loader, "connectionrestored", str -> CONNECTION_RESTORED = str); + loadString(loader, "warning_ifyouquit", str -> WARNING_IF_YOU_QUIT = str); + loadString(loader, "checking", str -> CHECKING = str); + loadString(loader, "openinpopupwindow", str -> OPEN_IN_POPUP_WINDOW = str); + loadString(loader, "create", str -> CREATE = str); + loadString(loader, "creatingyouraccount", str -> CREATING_YOUR_ACCOUNT = str); + loadString(loader, "day", str -> DAY = str); + loadString(loader, "month", str -> MONTH = str); + loadString(loader, "year", str -> YEAR = str); + loadString(loader, "create_welcome", str -> CREATE_WELCOME = str); + loadString(loader, "create_createanaccount", str -> CREATE_CREATE_AN_ACCOUNT = str); + loadString(loader, "create_displayname", str -> CREATE_DISPLAY_NAME = str); + loadString(loader, "create_password", str -> CREATE_PASSWORD = str); + loadString(loader, "create_password_confirm", str -> CREATE_PASSWORD_CONFIRM = str); + loadString(loader, "create_email", str -> CREATE_EMAIL = str); + loadString(loader, "create_email_confirm", str -> CREATE_EMAIL_CONFIRM = str); + loadString(loader, "create_age", str -> CREATE_AGE = str); + loadString(loader, "create_suggestions", str -> CREATE_SUGGESTIONS = str); + loadString(loader, "create_more_suggestions", str -> CREATE_MORE_SUGGESTIONS = str); + loadString(loader, "create_select_alternative", str -> CREATE_SELECT_ALTERNATIVE = str); + loadString(loader, "create_optin_news", str -> CREATE_OPT_IN_NEWS = str); + loadString(loader, "create_agreeterms", str -> CREATE_AGREE_TERMS = str); + loadString(loader, "create_u13terms", str -> CREATE_U13_TERMS = str); + loadString(loader, "login_username_email", str -> LOGIN_USERNAME_EMAIL = str); + loadString(loader, "login_username_tooltip", str -> LOGIN_USERNAME_TOOLTIP = str); + loadString(loader, "login_create_tooltip", str -> LOGIN_CREATE_TOOLTIP = str); + loadString(loader, "login_justplay_tooltip", str -> LOGIN_JUST_PLAY_TOOLTIP = str); + loadString(loader, "login_no_displayname", str -> LOGIN_NO_DISPLAY_NAME = str); + loadString(loader, "create_displayname_tooltip", str -> CREATE_DISPLAYNAME_TOOLTIP = str); + loadString(loader, "create_displayname_hint", str -> CREATE_DIPLAY_NAME_HINT = str); + loadString(loader, "create_password_tooltip", str -> CREATE_PASSWORD_TOOLTIP = str); + loadString(loader, "create_password_hint", str -> CREATE_PASSWORD_HINT = str); + loadString(loader, "create_password_confirm_tooltip", str -> CREATE_PASSWORD_CONFIRM_TOOLTIP = str); + loadString(loader, "create_email_tooltip", str -> CREATE_EMAIL_TOOLTIP = str); + loadString(loader, "create_email_confirm_tooltip", str -> CREATE_EMAIL_CONFIRM_TOOLTIP = str); + loadString(loader, "create_age_tooltip", str -> CREATE_AGE_TOOLTIP = str); + loadString(loader, "create_optin_news_tooltip", str -> CREATE_OPT_IN_NEWS_TOOLTIP = str); + loadString(loader, "create_username_unavailable", str -> CREATE_USERNAME_UNAVAILABLE = str); + loadString(loader, "create_username_available", str -> CREATE_USERNAME_AVAILABLE = str); + loadString(loader, "create_alert_namelength", str -> CREATE_ALERT_NAME_LENGTH = str); + loadString(loader, "create_alert_namechars", str -> CREATE_ALERT_NAME_CHARS = str); + loadString(loader, "create_alert_nameleadingspace", str -> CREATE_ALERT_NAME_LEADING_SPACE = str); + loadString(loader, "create_alert_doublespace", str -> CREATE_ALERT_DOUBLE_SPACE = str); + loadString(loader, "create_alert_passchars", str -> CREATE_ALERT_PASSCHARS = str); + loadString(loader, "create_alert_passrepeated", str -> CREATE_ALERT_PASS_REPEATED = str); + loadString(loader, "create_alert_passlength", str -> CREATE_ALERT_PASS_LENGTH = str); + loadString(loader, "create_alert_passcontainsname", str -> CREATE_ALERT_PASS_CONTAINS_NAME = str); + loadString(loader, "create_alert_passcontainsemail", str -> CREATE_ALERT_PASS_CONTAINS_EMAIL = str); + loadString(loader, "create_alert_passcontainsname_partial", str -> CREATE_ALERT_PASS_CONTAINS_NAME_PARTIAL = str); + loadString(loader, "create_alert_invalidemail", str -> CREATE_ALERT_INVALID_EMAIL = str); + loadString(loader, "create_alert_email_unavailable", str -> CREATE_ALERT_EMAIL_UNAVAILABLE = str); + loadString(loader, "create_alert_invaliddate", str -> CREATE_ALERT_INVALID_DATE = str); + loadString(loader, "create_alert_invalidage", str -> CREATE_ALERT_INVALID_AGE = str); + loadString(loader, "create_alert_yearrange", str -> CREATE_ALERT_YEAR_RANGE = str); + loadString(loader, "create_alert_mismatch", str -> CREATE_ALERT_MISMATCH = str); + loadString(loader, "create_passwordvalid", str -> PASSWORD_IS_VALID = str); + loadString(loader, "create_emailvalid", str -> CREATE_EMAIL_VALID = str); + loadString(loader, "create_account_success", str -> ACCOUNT_CREATED_SUCCESSFULLY = str); + loadString(loader, "invalid_name", str -> INVALID_NAME = str); + loadString(loader, "cannot_add_yourself", str -> CANNOT_ADD_YOURSELF = str); + loadString(loader, "unable_to_add_friend", str -> UNABLE_TO_ADD_FRIEND = str); + loadString(loader, "unable_to_add_ignore", str -> UNABLE_TO_ADD_IGNORE = str); + loadString(loader, "unable_to_delete_friend", str -> UNABLE_TO_DELETE_FRIEND = str); + loadString(loader, "unable_to_delete_ignore", str -> UNABLE_TO_DELETE_IGNORE = str); + loadString(loader, "friendlistfull", str -> FRIEND_LIST_FULL = str); + loadString(loader, "friendlistdupe", str -> FRIEND_LIST_DUPE = str); + loadString(loader, "friendnotfound", str -> FRIEND_NOT_FOUND = str); + loadString(loader, "ignorelistfull", str -> IGNORE_LIST_FULL = str); + loadString(loader, "ignorelistdupe", str -> IGNORE_LIST_DUPE = str); + loadString(loader, "ignorenotfound", str -> IGNORE_NOT_FOUND = str); + loadString(loader, "removeignorefirst", str -> REMOVE_FROM_IGNORE_FIRST = str); + loadString(loader, "removefriendfirst", str -> REMOVE_FRIEND_FIRST = str); + loadString(loader, "enterfriend_add", str -> ENTER_FRIEND_ADD = str); + loadString(loader, "enterfriend_del", str -> ENTER_FRIEND_DEL = str); + loadString(loader, "enterignore_add", str -> ENTER_IGNORE_ADD = str); + loadString(loader, "enterignore_del", str -> ENTER_IGNORE_DEL = str); + loadString(loader, "text_removed_from_game", str -> TEXT_REMOVED_FROM_GAME = str); + loadString(loader, "waitingfor_graphics", str -> WAITING_FOR_GRAPHICS = str); + loadString(loader, "waitingfor_fonts", str -> WAITING_FOR_FONTS = str); + loadString(loader, "waitingfor_soundeffects", str -> WAITING_FOR_SOUND_EFFECTS = str); + loadString(loader, "waitingfor_music", str -> WAITING_FOR_MUSIC = str); + loadString(loader, "waitingfor_extradata", str -> WAITING_FOR_EXTRA_DATA = str); + loadString(loader, "loading_graphics", str -> LOADING_GRAPHICS = str); + loadString(loader, "loading_fonts", str -> LOADING_FONTS = str); + loadString(loader, "loading_soundeffects", str -> LOADING_SOUND_EFFECTS = str); + loadString(loader, "loading_music", str -> LOADING_MUSIC = str); + loadString(loader, "loading_extradata", str -> LOADING_EXTRA_DATA = str); + loadString(loader, "unpacking_graphics", str -> UNPACKING_GRAPHICS = str); + loadString(loader, "unpacking_soundeffects", str -> UNPACKING_SOUND_EFFECTS = str); + loadString(loader, "unpacking_music", str -> UNPACKING_MUSIC = str); + loadString(loader, "instructions", str -> INSTRUCTIONS = str); + loadString(loader, "tutorial", str -> TUTORIAL = str); + loadString(loader, "sound_colon", str -> SOUND_COLON = str); + loadString(loader, "music_colon", str -> MUSIC_COLON = str); + loadString(loader, "fullscreen", str -> FULLSCREEN = str); + loadString(loader, "rankings", str -> RANKINGS = str); + loadString(loader, "achievements", str -> ACHIEVEMENTS = str); + loadString(loader, "watchintroduction", str -> WATCH_INTRODUCTION = str); + loadString(loader, "quit", str -> QUIT = str); + loadString(loader, "login_createaccount", str -> LOGIN_CREATE_ACCOUNT = str); + loadString(loader, "returntomainmenu", str -> RETURN_TO_MAIN_MENU = str); + loadString(loader, "pausemenu", str -> PAUSE_MENU = str); + loadString(loader, "optionsmenu_notpaused", str -> OPTIONS_MENU_NOT_PAUSED = str); + loadString(loader, "menu", str -> MENU = str); + loadString(loader, "startgame", str -> START_GAME = str); + loadString(loader, "endgame", str -> END_GAME = str); + loadString(loader, "endtutorial", str -> END_TUTORIAL = str); + loadString(loader, "ok", str -> OK = str); + loadString(loader, "entermultiplayerlobby", str -> ENTER_MULTIPLAYER_LOBBY = str); + loadString(loader, "returntogame", str -> RETURN_TO_GAME = str); + loadString(loader, "offerdraw", str -> OFFER_DRAW = str); + loadString(loader, "canceldraw", str -> CANCEL_DRAW = str); + loadString(loader, "acceptdraw", str -> ACCEPT_DRAW = str); + loadString(loader, "resign", str -> RESIGN = str); + loadString(loader, "returntolobby", str -> RETURN_TO_LOBBY = str); + loadString(loader, "cont", str -> CONT = str); + loadString(loader, "mouseoveranicon", str -> MOUSE_OVER_AN_ICON = str); + loadString(loader, "orbpoints", str -> ORB_POINTS = str); + loadString(loader, "orbpoints_colon", str -> ORB_POINTS_COLON = str); + loadString(loader, "secretachievement", str -> SECRET_ACHIEVEMENT = str); + loadString(loader, "mp_offerrematch", str -> MP_OFFER_REMATCH = str); + loadString(loader, "mp_offerrematch_unrated", str -> MP_OFFER_REMATCH_UNRATED = str); + loadString(loader, "mp_acceptrematch", str -> MP_ACCEPT_REMATCH = str); + loadString(loader, "mp_acceptrematch_unrated", str -> MP_ACCEPT_REMATCH_UNRATED = str); + loadString(loader, "mp_cancelrematch", str -> MP_CANCEL_REMATCH = str); + loadString(loader, "mp_cancelrematch_unrated", str -> MP_CANCEL_REMATCH_UNRATED = str); + loadString(loader, "mp_rematchnewgame", str -> MP_REMATCH_NEW_GAME = str); + loadString(loader, "mp_rematchnewgame_unrated", str -> MP_REMATCH_NEW_GAME_UNRATED = str); + loadString(loader, "mp_x_wantstodraw", str -> MP_X_WANTS_TO_DRAW = str); + loadString(loader, "mp_x_offersrematch", str -> MP_X_OFFERS_REMATCH = str); + loadString(loader, "mp_x_offersrematch_unrated", str -> MP_X_OFFERS_REMATCH_UNRATED = str); + loadString(loader, "mp_youofferrematch", str -> MP_YOU_OFFER_REMATCH = str); + loadString(loader, "mp_youofferrematch_unrated", str -> MP_YOU_OFFER_REMATCH_UNRATED = str); + loadString(loader, "mp_youofferdraw", str -> MP_YOU_OFFER_DRAW = str); + loadString(loader, "mp_youresigned", str -> MP_YOU_RESIGNED = str); + loadString(loader, "mp_x_hasresignedandleft", str -> MP_X_HAS_RESIGNED_AND_LEFT = str); + loadString(loader, "mp_x_hasresigned", str -> MP_X_HAS_RESIGNED = str); + loadString(loader, "mp_x_hasleft", str -> MP_X_HAS_LEFT = str); + loadString(loader, "click_to_quickchat", str -> CLICK_TO_QUICKCHAT = str); + loadString(loader, "autorespond", str -> AUTO_RESPOND = str); + loadString(loader, "quickchat_help", str -> QUICK_CHAT_HELP = str); + loadString(loader, "quickchat_help_title", str -> QUICK_CHAT_HELP_TITLE = str); + loadString(loader, "quickchat_shortcut_help,0", str -> QUICK_CHAT_SHORTCUT_HELP[0] = str); + loadString(loader, "quickchat_shortcut_help,1", str -> QUICK_CHAT_SHORTCUT_HELP[1] = str); + loadString(loader, "quickchat_shortcut_help,2", str -> QUICK_CHAT_SHORTCUT_HELP[2] = str); + loadString(loader, "quickchat_shortcut_help,3", str -> QUICK_CHAT_SHORTCUT_HELP[3] = str); + loadString(loader, "quickchat_shortcut_help,4", str -> QUICK_CHAT_SHORTCUT_HELP[4] = str); + loadString(loader, "quickchat_shortcut_help,5", str -> QUICK_CHAT_SHORTCUT_HELP[5] = str); + loadString(loader, "quickchat_shortcut_keys,0", str -> QUICK_CHAT_SHORTCUT_KEYS[0] = str); + loadString(loader, "quickchat_shortcut_keys,1", str -> QUICK_CHAT_SHORTCUT_KEYS[1] = str); + loadString(loader, "quickchat_shortcut_keys,2", str -> QUICK_CHAT_SHORTCUT_KEYS[2] = str); + loadString(loader, "quickchat_shortcut_keys,3", str -> QUICK_CHAT_SHORTCUT_KEYS[3] = str); + loadString(loader, "quickchat_shortcut_keys,4", str -> QUICK_CHAT_SHORTCUT_KEYS[4] = str); + loadString(loader, "quickchat_shortcut_keys,5", str -> QUICK_CHAT_SHORTCUT_KEYS[5] = str); + loadString(loader, "keychar_the_character_under_questionmark", str -> KEYCHAR_THE_CHARACTER_UNDER_QUESTION_MARK = str.charAt(0)); + loadString(loader, "rating_noratings", str -> RATING_NO_RATINGS = str); + loadString(loader, "rating_rating", str -> RATING_RATING = str); + loadString(loader, "rating_played", str -> RATING_PLAYED = str); + loadString(loader, "rating_won", str -> RATING_WON = str); + loadString(loader, "rating_lost", str -> RATING_LOST = str); + loadString(loader, "rating_drawn", str -> RATING_DRAWN = str); + loadString(loader, "fs_accept_beforeaccept", str -> FS_ACCEPT_BEFORE_ACCEPT = str); + loadString(loader, "fs_button_accept", str -> FS_BUTTON_ACCEPT = str); + loadString(loader, "fs_accept_afteraccept", str -> FS_ACCEPT_AFTER_ACCEPT = str); + loadString(loader, "fs_button_cancel", str -> FS_BUTTON_CANCEL = str); + loadString(loader, "fs_accept_aftercancel", str -> FS_ACCEPT_AFTER_CANCEL = str); + loadString(loader, "fs_accept_countdown_sing", str -> FS_ACCEPT_COUNTDOWN_SING = str); + loadString(loader, "fs_accept_countdown_pl", str -> FS_ACCEPT_COUNTDOWN_PL = str); + loadString(loader, "fs_nonmember", str -> FS_NONMEMBER = str); + loadString(loader, "fs_button_close", str -> FS_BUTTON_CLOSE = str); + loadString(loader, "fs_button_members", str -> FS_BUTTON_MEMBERS = str); + loadString(loader, "fs_unavailable", str -> FS_UNAVAILABLE = str); + loadString(loader, "fs_focus", str -> FS_FOCUS = str); + loadString(loader, "fs_timeout", str -> FS_TIMEOUT = str); + loadString(loader, "fs_button_tryagain", str -> FS_BUTTON_TRY_AGAIN = str); + loadString(loader, "hs_mode_name,0", str -> HS_MODE_NAMES[0] = str); + loadString(loader, "hs_mode_name,1", str -> HS_MODE_NAMES[1] = str); + loadString(loader, "hs_mode_name,2", str -> HS_MODE_NAMES[2] = str); + loadString(loader, "rating_mode_name,0", str -> RATING_MODE_NAMES[0] = str); + loadString(loader, "rating_mode_name,1", str -> RATING_MODE_NAMES[1] = str); + loadString(loader, "pleasewait_dotdotdot", str -> PLEASE_WAIT = str); + loadString(loader, "serviceunavailable", str -> SERVICE_UNAVAILABLE = str); + loadString(loader, "createtouse", str -> CREATE_TO_USE = str); + loadString(loader, "achievementsoffline", str -> ACHIEVEMENTS_OFFLINE = str); + loadString(loader, "warning", str -> WARNING = str); + loadString(loader, "DEFAULT_PLAYER_NAME", str -> DEFAULT_PLAYER_NAME = str); + loadString(loader, "discard", str -> DISCARD = str); + } + + public static void loadShatteredPlans(final ResourceLoader loader) { + loadString(loader, "achievement_names,0", str -> ACHIEVEMENT_NAMES[0] = str); + loadString(loader, "achievement_names,1", str -> ACHIEVEMENT_NAMES[1] = str); + loadString(loader, "achievement_names,2", str -> ACHIEVEMENT_NAMES[2] = str); + loadString(loader, "achievement_names,3", str -> ACHIEVEMENT_NAMES[3] = str); + loadString(loader, "achievement_names,4", str -> ACHIEVEMENT_NAMES[4] = str); + loadString(loader, "achievement_names,5", str -> ACHIEVEMENT_NAMES[5] = str); + loadString(loader, "achievement_names,6", str -> ACHIEVEMENT_NAMES[6] = str); + loadString(loader, "achievement_names,7", str -> ACHIEVEMENT_NAMES[7] = str); + loadString(loader, "achievement_names,8", str -> ACHIEVEMENT_NAMES[8] = str); + loadString(loader, "achievement_names,9", str -> ACHIEVEMENT_NAMES[9] = str); + loadString(loader, "achievement_names,10", str -> ACHIEVEMENT_NAMES[10] = str); + loadString(loader, "achievement_names,11", str -> ACHIEVEMENT_NAMES[11] = str); + loadString(loader, "achievement_names,12", str -> ACHIEVEMENT_NAMES[12] = str); + loadString(loader, "achievement_names,13", str -> ACHIEVEMENT_NAMES[13] = str); + loadString(loader, "achievement_names,14", str -> ACHIEVEMENT_NAMES[14] = str); + loadString(loader, "achievement_names,15", str -> ACHIEVEMENT_NAMES[15] = str); + loadString(loader, "achievement_names,16", str -> ACHIEVEMENT_NAMES[16] = str); + loadString(loader, "achievement_names,17", str -> ACHIEVEMENT_NAMES[17] = str); + loadString(loader, "achievement_names,18", str -> ACHIEVEMENT_NAMES[18] = str); + loadString(loader, "achievement_names,19", str -> ACHIEVEMENT_NAMES[19] = str); + loadString(loader, "achievement_names,20", str -> ACHIEVEMENT_NAMES[20] = str); + loadString(loader, "achievement_names,21", str -> ACHIEVEMENT_NAMES[21] = str); + loadString(loader, "achievement_names,22", str -> ACHIEVEMENT_NAMES[22] = str); + loadString(loader, "achievement_names,23", str -> ACHIEVEMENT_NAMES[23] = str); + loadString(loader, "achievement_names,24", str -> ACHIEVEMENT_NAMES[24] = str); + loadString(loader, "text_no_achievement", str -> TEXT_NO_ACHIEVEMENT = str); + loadString(loader, "achievement_criteria,0", str -> ACHIEVEMENT_CRITERIA[0] = str); + loadString(loader, "achievement_criteria,1", str -> ACHIEVEMENT_CRITERIA[1] = str); + loadString(loader, "achievement_criteria,2", str -> ACHIEVEMENT_CRITERIA[2] = str); + loadString(loader, "achievement_criteria,3", str -> ACHIEVEMENT_CRITERIA[3] = str); + loadString(loader, "achievement_criteria,4", str -> ACHIEVEMENT_CRITERIA[4] = str); + loadString(loader, "achievement_criteria,5", str -> ACHIEVEMENT_CRITERIA[5] = str); + loadString(loader, "achievement_criteria,6", str -> ACHIEVEMENT_CRITERIA[6] = str); + loadString(loader, "achievement_criteria,7", str -> ACHIEVEMENT_CRITERIA[7] = str); + loadString(loader, "achievement_criteria,8", str -> ACHIEVEMENT_CRITERIA[8] = str); + loadString(loader, "achievement_criteria,9", str -> ACHIEVEMENT_CRITERIA[9] = str); + loadString(loader, "achievement_criteria,10", str -> ACHIEVEMENT_CRITERIA[10] = str); + loadString(loader, "achievement_criteria,11", str -> ACHIEVEMENT_CRITERIA[11] = str); + loadString(loader, "achievement_criteria,12", str -> ACHIEVEMENT_CRITERIA[12] = str); + loadString(loader, "achievement_criteria,13", str -> ACHIEVEMENT_CRITERIA[13] = str); + loadString(loader, "achievement_criteria,14", str -> ACHIEVEMENT_CRITERIA[14] = str); + loadString(loader, "achievement_criteria,15", str -> ACHIEVEMENT_CRITERIA[15] = str); + loadString(loader, "achievement_criteria,16", str -> ACHIEVEMENT_CRITERIA[16] = str); + loadString(loader, "achievement_criteria,17", str -> ACHIEVEMENT_CRITERIA[17] = str); + loadString(loader, "achievement_criteria,18", str -> ACHIEVEMENT_CRITERIA[18] = str); + loadString(loader, "achievement_criteria,19", str -> ACHIEVEMENT_CRITERIA[19] = str); + loadString(loader, "achievement_criteria,20", str -> ACHIEVEMENT_CRITERIA[20] = str); + loadString(loader, "achievement_criteria,21", str -> ACHIEVEMENT_CRITERIA[21] = str); + loadString(loader, "achievement_criteria,22", str -> ACHIEVEMENT_CRITERIA[22] = str); + loadString(loader, "achievement_criteria,23", str -> ACHIEVEMENT_CRITERIA[23] = str); + loadString(loader, "achievement_criteria,24", str -> ACHIEVEMENT_CRITERIA[24] = str); + loadString(loader, "achievements_rated_only", str -> ACHIEVEMENTS_RATED_ONLY = str); + loadString(loader, "gameoptlabels,0", str -> GAMEOPT_LABELS[0] = str); + loadString(loader, "gameoptlabels,1", str -> GAMEOPT_LABELS[1] = str); + loadString(loader, "gameoptlabels,2", str -> GAMEOPT_LABELS[2] = str); + loadString(loader, "gameoptlabels,3", str -> GAMEOPT_LABELS[3] = str); + loadString(loader, "gameoptlabels,4", str -> GAMEOPT_LABELS[4] = str); + loadString(loader, "gameoptlabels,5", str -> GAMEOPT_LABELS[5] = str); + loadString(loader, "gameoptnames,1,0", str -> GAMEOPT_NAMES[1][0] = str); + loadString(loader, "gameoptnames,1,1", str -> GAMEOPT_NAMES[1][1] = str); + loadString(loader, "gameoptnames,1,2", str -> GAMEOPT_NAMES[1][2] = str); + loadString(loader, "gameoptnames,1,3", str -> GAMEOPT_NAMES[1][3] = str); + loadString(loader, "gameoptnames,1,4", str -> GAMEOPT_NAMES[1][4] = str); + loadString(loader, "gameoptnames,1,5", str -> GAMEOPT_NAMES[1][5] = str); + loadString(loader, "gameoptnames,1,6", str -> GAMEOPT_NAMES[1][6] = str); + loadString(loader, "gameoptnames,2,0", str -> GAMEOPT_NAMES[2][0] = str); + loadString(loader, "gameoptnames,2,1", str -> GAMEOPT_NAMES[2][1] = str); + loadString(loader, "gameoptnames,2,2", str -> GAMEOPT_NAMES[2][2] = str); + loadString(loader, "gameoptnames,2,3", str -> GAMEOPT_NAMES[2][3] = str); + loadString(loader, "gameoptnames,3,0", str -> GAMEOPT_NAMES[3][0] = str); + loadString(loader, "gameoptnames,3,1", str -> GAMEOPT_NAMES[3][1] = str); + loadString(loader, "gameoptnames,3,2", str -> GAMEOPT_NAMES[3][2] = str); + loadString(loader, "gameoptnames,3,3", str -> GAMEOPT_NAMES[3][3] = str); + loadString(loader, "gameoptnames,3,4", str -> GAMEOPT_NAMES[3][4] = str); + loadString(loader, "gameoptnames,4,0", str -> GAMEOPT_NAMES[4][0] = str); + loadString(loader, "gameoptnames,4,1", str -> GAMEOPT_NAMES[4][1] = str); + loadString(loader, "gametypeTooltips,0", str -> GAME_TYPE_TOOLTIPS[0] = str); + loadString(loader, "gametypeTooltips,1", str -> GAME_TYPE_TOOLTIPS[1] = str); + loadString(loader, "gametypeTooltips,2", str -> GAME_TYPE_TOOLTIPS[2] = str); + loadString(loader, "gametypeTooltips,3", str -> GAME_TYPE_TOOLTIPS[3] = str); + loadString(loader, "rulesetTooltips,0", str -> RULESET_TOOLTIPS[0] = str); + loadString(loader, "rulesetTooltips,1", str -> RULESET_TOOLTIPS[1] = str); + loadString(loader, "empire_names,0", str -> EMPIRE_NAMES[0] = str); + loadString(loader, "empire_names,1", str -> EMPIRE_NAMES[1] = str); + loadString(loader, "empire_names,2", str -> EMPIRE_NAMES[2] = str); + loadString(loader, "empire_names,3", str -> EMPIRE_NAMES[3] = str); + loadString(loader, "empire_names,4", str -> EMPIRE_NAMES[4] = str); + loadString(loader, "empire_names,5", str -> EMPIRE_NAMES[5] = str); + loadString(loader, "resource_names,0", str -> RESOURCE_NAMES[0] = str); + loadString(loader, "resource_names,1", str -> RESOURCE_NAMES[1] = str); + loadString(loader, "resource_names,2", str -> RESOURCE_NAMES[2] = str); + loadString(loader, "resource_names,3", str -> RESOURCE_NAMES[3] = str); + loadString(loader, "project_names,0", str -> PROJECT_NAMES[0] = str); + loadString(loader, "project_names,1", str -> PROJECT_NAMES[1] = str); + loadString(loader, "project_names,2", str -> PROJECT_NAMES[2] = str); + loadString(loader, "project_names,3", str -> PROJECT_NAMES[3] = str); + loadString(loader, "instructions_tabnames,0", str -> INSTRUCTIONS_TABNAMES[0] = str); + loadString(loader, "instructions_tabnames,1", str -> INSTRUCTIONS_TABNAMES[1] = str); + loadString(loader, "instructions_tabnames,2", str -> INSTRUCTIONS_TABNAMES[2] = str); + loadString(loader, "instructions_tabnames,3", str -> INSTRUCTIONS_TABNAMES[3] = str); + loadString(loader, "instructions_tabnames,4", str -> INSTRUCTIONS_TABNAMES[4] = str); + loadString(loader, "instructions_tabnames,5", str -> INSTRUCTIONS_TABNAMES[5] = str); + loadString(loader, "instructions_tabnames,6", str -> INSTRUCTIONS_TABNAMES[6] = str); + loadString(loader, "instructions_tabnames,7", str -> INSTRUCTIONS_TABNAMES[7] = str); + loadString(loader, "instructions_tabnames,8", str -> INSTRUCTIONS_TABNAMES[8] = str); + loadString(loader, "instructions_tabnames,9", str -> INSTRUCTIONS_TABNAMES[9] = str); + loadString(loader, "instructions_tabnames,10", str -> INSTRUCTIONS_TABNAMES[10] = str); + loadString(loader, "TEXT_INTRO0,0", str -> TEXT_INTRO_0[0] = str); + loadString(loader, "TEXT_INTRO0,1", str -> TEXT_INTRO_0[1] = str); + loadString(loader, "TEXT_INTRO1_START", str -> TEXT_INTRO_1_START = str); + loadString(loader, "TEXT_INTRO1_END", str -> TEXT_INTRO_1_END = str); + loadString(loader, "TEXT_INTRO2_START", str -> TEXT_INTRO_2_START = str); + loadString(loader, "TEXT_INTRO2_END", str -> TEXT_INTRO_2_END = str); + loadString(loader, "TEXT_INTRO3_START", str -> TEXT_INTRO_3_START = str); + loadString(loader, "TEXT_INTRO4_START", str -> TEXT_INTRO_4_START = str); + loadString(loader, "TEXT_INTRO4_END", str -> TEXT_INTRO_4_END = str); + loadString(loader, "text_skipintro", str -> TEXT_SKIP_INTRO = str); + loadString(loader, "pact_offer", str -> PACT_OFFER = str); + loadString(loader, "pact_accept", str -> PACT_ACCEPT = str); + loadString(loader, "pact_awaiting", str -> PACT_AWAITING = str); + loadString(loader, "pact_expires", str -> PACT_EXPIRES = str); + loadString(loader, "hint_select_src", str -> HINT_SELECT_SRC = str); + loadString(loader, "hint_select_dest", str -> HINT_SELECT_DEST = str); + loadString(loader, "hint_placement", str -> HINT_PLACEMENT = str); + loadString(loader, "hint_defensegrid", str -> HINT_DEFENSEGRID = str); + loadString(loader, "hint_terraform", str -> HINT_TERRAFORM = str); + loadString(loader, "hint_flare", str -> HINT_FLARE = str); + loadString(loader, "hint_select_gate_src", str -> HINT_SELECT_GATE_SRC = str); + loadString(loader, "hint_select_gate_dest", str -> HINT_SELECT_GATE_DEST = str); + loadString(loader, "hint_cancel", str -> HINT_CANCEL_PROJECT = str); + loadString(loader, "text_waitingforplayer", str -> TEXT_WAITING_FOR_PLAYER = str); + loadString(loader, "text_waitingforplayers", str -> WAITING_FOR_N_PLAYERS = str); + loadString(loader, "text_youhavebeendefeated", str -> TEXT_YOU_HAVE_BEEN_DEFEATED = str); + loadString(loader, "text_victory", str -> TEXT_VICTORY = str); + loadString(loader, "text_defeat", str -> TEXT_DEFEAT = str); + loadString(loader, "text_peace_short", str -> TEXT_PEACE_SHORT = str); + loadString(loader, "text_peace", str -> TEXT_PEACE = str); + loadString(loader, "text_peace2", str -> TEXT_PEACE_2 = str); + loadString(loader, "text_peace3", str -> TEXT_PEACE_3 = str); + loadString(loader, "text_playerHasWon", str -> TEXT_PLAYER_HAS_WON = str); + loadString(loader, "text_togglestats", str -> TEXT_TOGGLE_STATS = str); + loadString(loader, "text_togglestats2", str -> TEXT_TOGGLE_STATS_2 = str); + loadString(loader, "text_esctoexit", str -> TEXT_ESC_TO_EXIT = str); + loadString(loader, "text_defeated", str -> TEXT_DEFEATED = str); + loadString(loader, "text_resigned", str -> TEXT_RESIGNED = str); + loadString(loader, "text_join_final", str -> TEXT_JOIN_FINAL = str); + loadString(loader, "text_join", str -> TEXT_JOIN = str); + loadString(loader, "text_decimal", str -> TEXT_DECIMAL = str); + loadString(loader, "turn_ordinal", str -> TURN_ORDINAL = str); + loadString(loader, "turn_name", str -> TURN_NAME = str); + loadString(loader, "turn_name_first", str -> TURN_NAME_FIRST = str); + loadString(loader, "turnObjective", str -> TURN_OBJECTIVE = str); + loadString(loader, "turnOnePoint", str -> TURN_ONE_POINT = str); + loadString(loader, "turnPoints", str -> TURN_POINTS = str); + loadString(loader, "turnFewerShips", str -> TURN_FEWER_SHIPS = str); + loadString(loader, "turn_name1,0", str -> TURN_NAMES_1[0] = str); + loadString(loader, "turn_name1,1", str -> TURN_NAMES_1[1] = str); + loadString(loader, "turn_name1,2", str -> TURN_NAMES_1[2] = str); + loadString(loader, "turn_name1,3", str -> TURN_NAMES_1[3] = str); + loadString(loader, "turn_name1,4", str -> TURN_NAMES_1[4] = str); + loadString(loader, "turn_name1,5", str -> TURN_NAMES_1[5] = str); + loadString(loader, "turn_name1,6", str -> TURN_NAMES_1[6] = str); + loadString(loader, "turn_name1,7", str -> TURN_NAMES_1[7] = str); + loadString(loader, "turn_name1,8", str -> TURN_NAMES_1[8] = str); + loadString(loader, "turn_name1,9", str -> TURN_NAMES_1[9] = str); + loadString(loader, "turn_name1,10", str -> TURN_NAMES_1[10] = str); + loadString(loader, "turn_name1,11", str -> TURN_NAMES_1[11] = str); + loadString(loader, "turn_name1,12", str -> TURN_NAMES_1[12] = str); + loadString(loader, "turn_name1,13", str -> TURN_NAMES_1[13] = str); + loadString(loader, "turn_name1,14", str -> TURN_NAMES_1[14] = str); + loadString(loader, "turn_name1,15", str -> TURN_NAMES_1[15] = str); + loadString(loader, "turn_name1,16", str -> TURN_NAMES_1[16] = str); + loadString(loader, "turn_name1,17", str -> TURN_NAMES_1[17] = str); + loadString(loader, "turn_name1,18", str -> TURN_NAMES_1[18] = str); + loadString(loader, "turn_name1,19", str -> TURN_NAMES_1[19] = str); + loadString(loader, "turn_name1,20", str -> TURN_NAMES_1[20] = str); + loadString(loader, "turn_name1,21", str -> TURN_NAMES_1[21] = str); + loadString(loader, "turn_name2,0", str -> TURN_NAMES_2[0] = str); + loadString(loader, "turn_name2,1", str -> TURN_NAMES_2[1] = str); + loadString(loader, "turn_name2,2", str -> TURN_NAMES_2[2] = str); + loadString(loader, "turn_name2,3", str -> TURN_NAMES_2[3] = str); + loadString(loader, "turn_name2,4", str -> TURN_NAMES_2[4] = str); + loadString(loader, "turn_name2,5", str -> TURN_NAMES_2[5] = str); + loadString(loader, "turn_name2,6", str -> TURN_NAMES_2[6] = str); + loadString(loader, "turn_name2,7", str -> TURN_NAMES_2[7] = str); + loadString(loader, "turn_name2,8", str -> TURN_NAMES_2[8] = str); + loadString(loader, "turn_name2,9", str -> TURN_NAMES_2[9] = str); + loadString(loader, "turn_name2,10", str -> TURN_NAMES_2[10] = str); + loadString(loader, "turn_name2,11", str -> TURN_NAMES_2[11] = str); + loadString(loader, "turn_name2,12", str -> TURN_NAMES_2[12] = str); + loadString(loader, "turn_name2,13", str -> TURN_NAMES_2[13] = str); + loadString(loader, "turn_name2,14", str -> TURN_NAMES_2[14] = str); + loadString(loader, "turn_name2,15", str -> TURN_NAMES_2[15] = str); + loadString(loader, "turn_name2,16", str -> TURN_NAMES_2[16] = str); + loadString(loader, "turn_name2,17", str -> TURN_NAMES_2[17] = str); + loadString(loader, "turn_name2,18", str -> TURN_NAMES_2[18] = str); + loadString(loader, "derelict", str -> DERELICT = str); + loadString(loader, "text_instructions0", str -> TEXT_INSTRUCTIONS_0 = str); + loadString(loader, "text_instructions_glossary1", str -> TEXT_INSTRUCTIONS_GLOSSARY_1 = str); + loadString(loader, "text_instructions_glossary2", str -> TEXT_INSTRUCTIONS_GLOSSARY_2 = str); + loadString(loader, "text_instructions_mv_time", str -> TEXT_INSTRUCTIONS_MV_TIME = str); + loadString(loader, "text_instructions_mv_wormhole", str -> TEXT_INSTRUCTIONS_MV_WORMHOLE = str); + loadString(loader, "text_instructions_mv_frame", str -> TEXT_INSTRUCTIONS_MV_FRAME = str); + loadString(loader, "text_instructions_mv_ready", str -> TEXT_INSTRUCTIONS_MV_READY = str); + loadString(loader, "text_instructions_mv_order", str -> TEXT_INSTRUCTIONS_MV_ORDER = str); + loadString(loader, "text_instructions_sf_outgoing", str -> TEXT_INSTRUCTIONS_SF_OUTGOING = str); + loadString(loader, "text_instructions_sf_garrison", str -> TEXT_INSTRUCTIONS_SF_GARRISON = str); + loadString(loader, "text_instructions_sf_name", str -> TEXT_INSTRUCTIONS_SF_NAME = str); + loadString(loader, "text_instructions_sf_resources", str -> TEXT_INSTRUCTIONS_SF_RESOURCES = str); + loadString(loader, "text_instructions_sf_incoming", str -> TEXT_INSTRUCTIONS_SF_INCOMING = str); + loadString(loader, "text_instructions_icon_terraformed", str -> TEXT_INSTRUCTIONS_ICON_TERRAFORMED = str); + loadString(loader, "text_instructions_icon_neutral", str -> TEXT_INSTRUCTIONS_ICON_NEUTRAL = str); + loadString(loader, "text_instructions_icon_homeworld", str -> TEXT_INSTRUCTIONS_ICON_HOMEWORLD = str); + loadString(loader, "text_instructions_placement", str -> TEXT_INSTRUCTIONS_PLACEMENT = str); + loadString(loader, "text_instructions_movement", str -> TEXT_INSTRUCTIONS_MOVEMENT = str); + loadString(loader, "text_instructions_projects", str -> TEXT_INSTRUCTIONS_PROJECTS = str); + loadString(loader, "text_instructions_fleetsize", str -> TEXT_INSTRUCTIONS_FLEETSIZE = str); + loadString(loader, "text_instructions_endturn", str -> TEXT_INSTRUCTIONS_END_TURN = str); + loadString(loader, "text_instructions_hotkeys", str -> TEXT_INSTRUCTIONS_HOTKEYS = str); + loadString(loader, "text_instructions_stats", str -> TEXT_INSTRUCTIONS_STATS = str); + loadString(loader, "text_instructions_project_metal", str -> TEXT_INSTRUCTIONS_PROJECT_METAL = str); + loadString(loader, "text_instructions_project_biomass", str -> TEXT_INSTRUCTIONS_PROJECT_BIOMASS = str); + loadString(loader, "text_instructions_project_energy", str -> TEXT_INSTRUCTIONS_PROJECT_ENERGY = str); + loadString(loader, "text_instructions_project_exotics", str -> TEXT_INSTRUCTIONS_PROJECT_EXOTICS = str); + loadString(loader, "text_instructions_animation", str -> TEXT_INSTRUCTIONS_ANIMATION = str); + loadString(loader, "text_instructions_animation_fleetmove", str -> TEXT_INSTRUCTIONS_ANIMATION_FLEETMOVE = str); + loadString(loader, "text_instructions_animation_combat", str -> TEXT_INSTRUCTIONS_ANIMATION_COMBAT = str); + loadString(loader, "text_instructions_animation_damaged", str -> TEXT_INSTRUCTIONS_ANIMATION_DAMAGED = str); + loadString(loader, "text_instructions_animation_captured", str -> TEXT_INSTRUCTIONS_ANIMATION_CAPTURED = str); + loadString(loader, "text_instructions_animation_project", str -> TEXT_INSTRUCTIONS_ANIMATION_PROJECT = str); + loadString(loader, "text_instructions_gametype", str -> TEXT_INSTRUCTIONS_GAME_TYPE = str); + loadString(loader, "text_instructions_classic", str -> TEXT_INSTRUCTIONS_CLASSIC = str); + loadString(loader, "text_instructions_classic_stellarbomb", str -> TEXT_INSTRUCTIONS_CLASSIC_STELLAR_BOMB = str); + loadString(loader, "text_animating_moves", str -> TEXT_ANIMATING_MOVES = str); + loadString(loader, "text_animating_combat", str -> TEXT_ANIMATING_COMBAT = str); + loadString(loader, "text_animating_results", str -> SHOWING_COMBAT_RESULTS = str); + loadString(loader, "text_animating_collapse", str -> TEXT_ANIMATING_COLLAPSE = str); + loadString(loader, "tutorial_continue", str -> TUTORIAL_CONTINUE = str); + loadString(loader, "tutorial_continue2", str -> TUTORIAL_CONTINUE_2 = str); + loadString(loader, "tutorial_continue3", str -> TUTORIAL_CONTINUE_3 = str); + loadString(loader, "tutorial_continuekey", str -> TUTORIAL_CONTINUE_KEY = str); + loadString(loader, "tutorial_balanced", str -> TUTORIAL_BALANCED = str); + loadString(loader, "tutorial_shortfall1", str -> TUTORIAL_SHORTFALL1 = str); + loadString(loader, "tutorial_shortfall2a", str -> TUTORIAL_SHORTFALL2A = str); + loadString(loader, "tutorial_shortfall2b", str -> TUTORIAL_SHORTFALL_2B = str); + loadString(loader, "tutorial_retreating_single", str -> FLEET_HAS_RETREATED_TO = str); + loadString(loader, "tutorial_retreating_multiple", str -> TUTORIAL_RETREATING_MULTIPLE = str); + loadString(loader, "tutorial_lost_none", str -> TUTORIAL_LOST_NONE = str); + loadString(loader, "tutorial_lost_single", str -> TUTORIAL_LOST_SINGLE = str); + loadString(loader, "tutorial_lost_multiple", str -> TUTORIAL_LOST_MULTIPLE = str); + loadString(loader, "tutorial_capture_all", str -> TUTORIAL_CAPTURE_ALL = str); + loadString(loader, "tutorial_exit", str -> TUTORIAL_EXIT = str); + loadString(loader, "tabname_territories", str -> TAB_NAME_PRODUCTION = str); + loadString(loader, "tabname_uioptions", str -> TAB_NAME_UI_OPTIONS = str); + loadString(loader, "tabname_fleetinfo", str -> TAB_NAME_FLEET_INFO = str); + loadString(loader, "tabname_diplomacy", str -> TAB_NAME_DIPLOMACY = str); + loadString(loader, "tabname_projects", str -> TAB_NAME_PROJECTS = str); + loadString(loader, "tabname_messages", str -> TAB_NAME_MESSAGES = str); + loadString(loader, "tabname_victory", str -> TAB_NAME_VICTORY = str); + loadString(loader, "message_incoming_offers", str -> MESSAGE_INCOMING_OFFERS = str); + loadString(loader, "text_enemyproduction", str -> TEXT_ENEMY_PRODUCTION = str); + loadString(loader, "text_ships", str -> TEXT_SHIPS = str); + loadString(loader, "text_production", str -> TEXT_PRODUCTION = str); + loadString(loader, "text_systems", str -> TEXT_SYSTEMS = str); + loadString(loader, "text_overview", str -> TEXT_OVERVIEW = str); + loadString(loader, "text_ready", str -> TEXT_READY = str); + loadString(loader, "text_pending", str -> PENDING = str); + loadString(loader, "text_notavailable", str -> TEXT_NOT_AVAILABLE = str); + loadString(loader, "text_percentage", str -> TEXT_PERCENTAGE = str); + loadString(loader, "text_ordinals,0", str -> TEXT_ORDINALS[0] = str); + loadString(loader, "text_ordinals,1", str -> TEXT_ORDINALS[1] = str); + loadString(loader, "text_ordinals,2", str -> TEXT_ORDINALS[2] = str); + loadString(loader, "text_ordinals,3", str -> TEXT_ORDINALS[3] = str); + loadString(loader, "text_ordinals,4", str -> TEXT_ORDINALS[4] = str); + loadString(loader, "text_ordinals,5", str -> TEXT_ORDINALS[5] = str); + loadString(loader, "text_error", str -> TEXT_ERROR = str); + loadString(loader, "text_stat_max_total_fleet_size", str -> TEXT_STAT_MAX_TOTAL_FLEET_SIZE = str); + loadString(loader, "text_stat_ships_destroyed", str -> TEXT_STAT_SHIPS_DESTROYED = str); + loadString(loader, "text_stat_ships_lost", str -> TEXT_STAT_SHIPS_LOST = str); + loadString(loader, "text_stat_avg_move_size", str -> TEXT_STAT_AVG_MOVE_SIZE = str); + loadString(loader, "text_stat_max_production", str -> TEXT_STAT_MAX_PRODUCTION = str); + loadString(loader, "text_stat_ships_constructed", str -> TEXT_STAT_SHIPS_CONSTRUCTED = str); + loadString(loader, "text_stat_projects_used", str -> TEXT_STAT_PROJECTS_USED = str); + loadString(loader, "text_stat_research_wasted", str -> TEXT_STAT_RESEARCH_WASTED = str); + loadString(loader, "text_stat_attacks_successful", str -> TEXT_STAT_ATTACKS_SUCCESSFUL = str); + loadString(loader, "text_stat_attacks_failed", str -> TEXT_STAT_ATTACKS_FAILED = str); + loadString(loader, "text_stat_defences_successful", str -> TEXT_STAT_DEFENCES_SUCCESSFUL = str); + loadString(loader, "text_stat_defences_failed", str -> TEXT_STAT_DEFENCES_FAILED = str); + loadString(loader, "text_stat_efficiency", str -> TEXT_STAT_EFFICIENCY = str); + loadString(loader, "text_stat_fluidity", str -> TEXT_STAT_FLUIDITY = str); + loadString(loader, "text_stat_aggressiveness", str -> TEXT_STAT_AGGRESSIVENESS = str); + loadString(loader, "text_stat_solidity", str -> TEXT_STAT_SOLIDITY = str); + loadString(loader, "text_stat_desc_max_total_fleet_size", str -> TEXT_STAT_DESC_MAX_TOTAL_FLEET_SIZE = str); + loadString(loader, "text_stat_desc_ships_destroyed", str -> TEXT_STAT_DESC_SHIPS_DESTROYED = str); + loadString(loader, "text_stat_desc_ships_lost", str -> TEXT_STAT_DESC_SHIPS_LOST = str); + loadString(loader, "text_stat_desc_avg_move_size", str -> TEXT_STAT_DESC_AVG_MOVE_SIZE = str); + loadString(loader, "text_stat_desc_max_production", str -> TEXT_STAT_DESC_MAX_PRODUCTION = str); + loadString(loader, "text_stat_desc_ships_constructed", str -> TEXT_STAT_DESC_SHIPS_CONSTRUCTED = str); + loadString(loader, "text_stat_desc_projects_used", str -> TEXT_STAT_DESC_PROJECTS_USED = str); + loadString(loader, "text_stat_desc_research_wasted", str -> TEXT_STAT_DESC_RESEARCH_WASTED = str); + loadString(loader, "text_stat_desc_attacks_successful", str -> TEXT_STAT_DESC_ATTACKS_SUCCESSFUL = str); + loadString(loader, "text_stat_desc_attacks_failed", str -> TEXT_STAT_DESC_ATTACKS_FAILED = str); + loadString(loader, "text_stat_desc_defences_successful", str -> TEXT_STAT_DESC_DEFENCES_SUCCESSFUL = str); + loadString(loader, "text_stat_desc_defences_failed", str -> TEXT_STAT_DESC_DEFENCES_FAILED = str); + loadString(loader, "text_stat_desc_efficiency", str -> TEXT_STAT_DESC_EFFICIENCY = str); + loadString(loader, "text_stat_desc_fluidity", str -> TEXT_STAT_DESC_FLUIDITY = str); + loadString(loader, "text_stat_desc_aggressiveness", str -> TEXT_STAT_DESC_AGGRESSIVENESS = str); + loadString(loader, "text_stat_desc_solidity", str -> TEXT_STAT_DESC_SOLIDITY = str); + loadString(loader, "rated_membersonly", str -> RATED_MEMBERS_ONLY = str); + loadString(loader, "text_skirmish", str -> TEXT_SKIRMISH = str); + loadString(loader, "text_totalplayers", str -> TEXT_TOTAL_PLAYERS = str); + loadString(loader, "text_human_players", str -> TEXT_HUMAN_PLAYERS = str); + loadString(loader, "text_map_hex", str -> TEXT_MAP_HEX = str); + loadString(loader, "text_map_sol", str -> TEXT_MAP_SOL = str); + loadString(loader, "text_map_points", str -> TEXT_MAP_POINTS = str); + loadString(loader, "text_map_derelicts", str -> TEXT_MAP_DERELICTS = str); + loadString(loader, "text_garrison_yes", str -> TEXT_GARRISON_YES = str); + loadString(loader, "text_garrison_no", str -> TEXT_GARRISON_NO = str); + loadString(loader, "text_skirmish_start", str -> START_SKIRMISH = str); + loadString(loader, "track_name_new", str -> TRACK_NAME_NEW = str); + loadString(loader, "track_name_old", str -> TRACK_NAME_OLD = str); + loadString(loader, "text_showChat", str -> TEXT_SHOW_CHAT = str); + loadString(loader, "text_hideChat", str -> TEXT_HIDE_CHAT = str); + loadString(loader, "aichat,0,0", str -> AI_CHAT[0][0] = str); + loadString(loader, "aichat,1,0", str -> AI_CHAT[1][0] = str); + loadString(loader, "aichat,2,0", str -> AI_CHAT[2][0] = str); + loadString(loader, "aichat,3,0", str -> AI_CHAT[3][0] = str); + loadString(loader, "aichat,4,0", str -> AI_CHAT[4][0] = str); + loadString(loader, "aichat,5,0", str -> AI_CHAT[5][0] = str); + loadString(loader, "aichat,6,0", str -> AI_CHAT[6][0] = str); + loadString(loader, "aichat,7,0", str -> AI_CHAT[7][0] = str); + loadString(loader, "aichat,8,0", str -> AI_CHAT[8][0] = str); + loadString(loader, "aichat,9,0", str -> AI_CHAT[9][0] = str); + loadString(loader, "aichat,10,0", str -> AI_CHAT[10][0] = str); + loadString(loader, "aichat,11,0", str -> AI_CHAT[11][0] = str); + loadString(loader, "aichat,12,0", str -> AI_CHAT[12][0] = str); + loadString(loader, "aichat,13,0", str -> AI_CHAT[13][0] = str); + loadString(loader, "aichat,14,0", str -> AI_CHAT[14][0] = str); + loadString(loader, "aichat,15,0", str -> AI_CHAT[15][0] = str); + loadString(loader, "aichat,16,0", str -> AI_CHAT[16][0] = str); + loadString(loader, "aichat,17,0", str -> AI_CHAT[17][0] = str); + loadString(loader, "aichat,18,0", str -> AI_CHAT[18][0] = str); + loadString(loader, "aichat,19,0", str -> AI_CHAT[19][0] = str); + loadString(loader, "aichat,19,1", str -> AI_CHAT[19][1] = str); + loadString(loader, "aichat,20,0", str -> AI_CHAT[20][0] = str); + loadString(loader, "aichat,21,0", str -> AI_CHAT[21][0] = str); + loadString(loader, "aichat,22,0", str -> AI_CHAT[22][0] = str); + loadString(loader, "aichat,23,0", str -> AI_CHAT[23][0] = str); + loadString(loader, "aichat,24,0", str -> AI_CHAT[24][0] = str); + loadString(loader, "aichat,24,1", str -> AI_CHAT[24][1] = str); + loadString(loader, "aichat,24,2", str -> AI_CHAT[24][2] = str); + loadString(loader, "aichat,25,0", str -> AI_CHAT[25][0] = str); + loadString(loader, "aichat,26,0", str -> AI_CHAT[26][0] = str); + loadString(loader, "aitypes,0", str -> AI_TYPES[0] = str); + loadString(loader, "aitypes,1", str -> AI_TYPES[1] = str); + loadString(loader, "aitypes,2", str -> AI_TYPES[2] = str); + loadString(loader, "aitypes,3", str -> AI_TYPES[3] = str); + loadString(loader, "aitypes,4", str -> AI_TYPES[4] = str); + loadString(loader, "aitypes,5", str -> AI_TYPES[5] = str); + loadString(loader, "aitypes,6", str -> AI_TYPES[6] = str); + loadString(loader, "aitypes,7", str -> AI_TYPES[7] = str); + loadString(loader, "aitypes,8", str -> AI_TYPES[8] = str); + loadString(loader, "tooltipIncome,0", str -> TOOLTIP_INCOME[0] = str); + loadString(loader, "tooltipIncome,1", str -> TOOLTIP_INCOME[1] = str); + loadString(loader, "tooltipIncome,2", str -> TOOLTIP_INCOME[2] = str); + loadString(loader, "tooltipIncome,3", str -> TOOLTIP_INCOME[3] = str); + loadString(loader, "tooltipIncomingLimiting", str -> TOOLTIP_INCOME_LIMITING = str); + loadString(loader, "tooltipTotalFleetProduction", str -> TOOLTIP_TOTAL_FLEET_PRODUCTION = str); + loadString(loader, "tooltipPlaceFleets", str -> TOOLTIP_PLACE_FLEETS = str); + loadString(loader, "tooltipPlaceFleetsStop", str -> TOOLTIP_PLACE_FLEET_STOP = str); + loadString(loader, "tooltipFleetsRemaining", str -> TOOLTIP_FLEETS_REMAINING = str); + loadString(loader, "tooltipOneFleetRemaining", str -> TOOLTIP_ONE_FLEET_REMAINING = str); + loadString(loader, "tooltipAllFleetsPlaced", str -> TOOLTIP_ALL_FLEETS_PLACED = str); + loadString(loader, "tooltipOfferTreaty", str -> TOOLTIP_OFFER_TREATY = str); + loadString(loader, "tooltipAcceptTreaty", str -> TOOLTIP_ACCEPT_TREATY = str); + loadString(loader, "tooltipWaitTreaty", str -> TOOLTIP_WAIT_TREATY = str); + loadString(loader, "tooltipPartiallyComplete", str -> TOOLTIP_PARTIALLY_COMPLETE = str); + loadString(loader, "tooltipProjectComplete", str -> TOOLTIP_PROJECT_COMPLETE = str); + loadString(loader, "tooltipProjectPending", str -> TOOLTIP_PROJECT_PENDING = str); + loadString(loader, "tooltipProductionButtonShow", str -> TOOLTIP_PRODUCTION_BUTTON_SHOW = str); + loadString(loader, "tooltipProjectsButtonShow", str -> TOOLTIP_PROJECTS_BUTTON_SHOW = str); + loadString(loader, "tooltipDiplomacyButtonShow", str -> TOOLTIP_DIPLOMACY_BUTTON_SHOW = str); + loadString(loader, "tooltipFleetInfoButtonShow", str -> TOOLTIP_FLEET_INFO_BUTTON_SHOW = str); + loadString(loader, "tooltipVictoryButtonShow", str -> TOOLTIP_VICTORY_BUTTON_SHOW = str); + loadString(loader, "tooltipProductionButtonHide", str -> TOOLTIP_PRODUCTION_BUTTON_HIDE = str); + loadString(loader, "tooltipProjectsButtonHide", str -> TOOLTIP_PROJECTS_BUTTON_HIDE = str); + loadString(loader, "tooltipDiplomacyButtonHide", str -> TOOLTIP_DIPLOMACY_BUTTON_HIDE = str); + loadString(loader, "tooltipFleetInfoButtonHide", str -> TOOLTIP_FLEET_INFO_BUTTON_HIDE = str); + loadString(loader, "tooltipEndTurn", str -> TOOLTIP_END_TURN = str); + loadString(loader, "tooltipVictoryPaneManyMany", str -> TOOLTIP_VICTORY_PANE_MANY_MANY = str); + loadString(loader, "tooltipVictoryPaneOneOne", str -> ONE_POINT_1_PER_TURN = str); + loadString(loader, "tooltipVictoryPaneOneMany", str -> TOOLTIP_VICTORY_PANE_ONE_MANY = str); + loadString(loader, "tooltipVictoryPaneManyOne", str -> N_POINTS_1_PER_TURN = str); + loadString(loader, "tooltipProjectedWinner", str -> TOOLTIP_PROJECTED_WINNER = str); + loadString(loader, "tooltipAnimAutoPlayIsOn", str -> TOOLTIP_ANIM_AUTO_PLAY_IS_ON = str); + loadString(loader, "tooltipAnimAutoPlayIsOff", str -> TOOLTIP_ANIM_AUTO_PLAY_IS_OFF = str); + loadString(loader, "tooltipAnimClickToPlay", str -> TOOLTIP_ANIM_CLICK_TO_PLAY = str); + loadString(loader, "tooltipAnimClickToStop", str -> TOOLTIP_ANIM_CLICK_TO_STOP = str); + loadString(loader, "tooltipAnimSpeedIsNormal", str -> TOOLTIP_ANIM_SPEED_IS_NORMAL = str); + loadString(loader, "tooltipAnimSpeedIsDouble", str -> TOOLTIP_ANIM_SPEED_IS_DOUBLE = str); + loadString(loader, "victoryTargetPoints", str -> VICTORY_TARGET_POINTS = str); + loadString(loader, "victoryInX", str -> VICTORY_IN_X = str); + loadString(loader, "victoryTurnsRemaining", str -> VICTORY_TURNS_REMAINING = str); + loadString(loader, "victorySolEmpty", str -> VICTORY_SOL_EMPTY = str); + loadString(loader, "victorySolOwned", str -> VICTORY_SOL_OWNED = str); + } + + private static byte[] load(final ResourceLoader loader, final String var0) { + return loader.getResource("", var0); + } + + private static void loadString(final ResourceLoader loader, final String key, final Consumer setter) { + final byte[] data = load(loader, key); + if (data != null) { + setter.accept(Strings.decode1252String(data)); + } + } + + @SuppressWarnings("unused") + public static final class AIMessage { + public static final int NONE = -1; + public static final int REJECT_TOO_STRONG = 0; + public static final int REJECT_ENEMY_ALLY = 1; + public static final int REJECT_TOO_WEAK = 2; + public static final int REJECT_WANT_CAPTURE = 3; + public static final int ACCEPT_HARMLESS = 4; + public static final int ACCEPT_COMMON_ENEMY = 5; + public static final int ACCEPT_NEUTRAL = 6; + public static final int ACCEPT_INTIMIDATED = 7; + public static final int REQUEST_COMMON_ENEMY = 8; + public static final int REQUEST_LEADERS = 9; + public static final int ACCEPTED_CEASE_CONFLICT = 10; + public static final int ACCEPTED_COMMON_ENEMY = 11; + public static final int ACCEPTED_COORDINATE = 12; + public static final int AGGRESSIVE_1 = 13; + public static final int AGGRESSIVE_2 = 14; + public static final int DEFENSIVE_1 = 15; + public static final int DEFENSIVE_2 = 16; + public static final int OPTIMISTIC = 17; + public static final int DO_NOT_INTERFERE = 18; + public static final int ATTACK_SUCCESS = 19; + public static final int ATTACK_FAILURE = 20; + public static final int DEFENSE_SUCCESS = 21; + public static final int ATTACK_MISTAKE = 22; + public static final int WANT_SYSTEM = 23; + public static final int CONFIDENT_THREAT = 24; + public static final int ANGRY_WARNING = 25; + public static final int ANGRY_PLEA = 26; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/AchievementNotification.java b/src/main/java/funorb/shatteredplans/client/AchievementNotification.java new file mode 100644 index 0000000..0403e62 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/AchievementNotification.java @@ -0,0 +1,9 @@ +package funorb.shatteredplans.client; + +public final class AchievementNotification { + public final int achievementIndex; + + public AchievementNotification(final int achievementIndex) { + this.achievementIndex = achievementIndex; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/AuthMode.java b/src/main/java/funorb/shatteredplans/client/AuthMode.java new file mode 100644 index 0000000..f4fc156 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/AuthMode.java @@ -0,0 +1,15 @@ +package funorb.shatteredplans.client; + +import org.intellij.lang.annotations.MagicConstant; + +public final class AuthMode { + public static final int USER_ID = 2; + public static final int EMAIL = 3; + + @MagicConstant(valuesFromClass = AuthMode.class) + public final int value; + + public AuthMode(@MagicConstant(valuesFromClass = AuthMode.class) final int value) { + this.value = value; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/CombatEngagementAnimationState.java b/src/main/java/funorb/shatteredplans/client/CombatEngagementAnimationState.java new file mode 100644 index 0000000..77d7e2f --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/CombatEngagementAnimationState.java @@ -0,0 +1,56 @@ +package funorb.shatteredplans.client; + +import funorb.shatteredplans.client.game.CombatEngagementLog; +import funorb.shatteredplans.game.Player; +import funorb.shatteredplans.map.StarSystem; + +import java.util.Arrays; + +public final class CombatEngagementAnimationState { + public final int highestFleetsAtCombatStart; + public final Player victor; + public final int totalKills; + public final int fleetsAtCombatEnd; + public final Player ownerAtCombatStart; + public final Player[] players; + public final int[] fleetsAtCombatStart; + public final StarSystem system; + + public int totalFleets; + public int[] fleets; + public Player selectedPlayer; + + public CombatEngagementAnimationState(final CombatEngagementLog log) { + this.fleetsAtCombatStart = log.fleetsAtCombatStart; + this.ownerAtCombatStart = log.ownerAtCombatStart; + this.fleetsAtCombatEnd = log.fleetsAtCombatEnd; + this.players = log.players; + this.victor = log.victor; + this.system = log.system; + this.totalKills = log.totalKills; + this.highestFleetsAtCombatStart = Arrays.stream(this.fleetsAtCombatStart).max().orElse(0); + this.reset(); + } + + public void reset() { + this.fleets = this.fleetsAtCombatStart.clone(); + this.totalFleets = Arrays.stream(this.fleetsAtCombatStart).sum(); + + if (this.players.length == 1) { + this.totalFleets = 0; + Arrays.fill(this.fleets, 0); + } else { + this.selectedPlayer = this.players[ShatteredPlansClient.randomIntBounded(this.players.length - 1)]; + if (this.victor == this.selectedPlayer) { + this.selectedPlayer = this.players[this.players.length - 1]; + } + + final int victorIndex = this.victor == null + ? this.fleetsAtCombatStart.length - 1 + : this.victor.index; + this.fleets[victorIndex] -= this.fleetsAtCombatEnd; + this.totalFleets -= this.fleetsAtCombatEnd; + --this.totalFleets; + } + } +} diff --git a/src/main/java/funorb/shatteredplans/client/FrameClock.java b/src/main/java/funorb/shatteredplans/client/FrameClock.java new file mode 100644 index 0000000..a43197c --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/FrameClock.java @@ -0,0 +1,69 @@ +package funorb.shatteredplans.client; + +public final class FrameClock { + private static final long NANOS_PER_MILLI = 1_000_000L; + private static final long NANOS_PER_SECOND = 1000L * NANOS_PER_MILLI; + private static final long TARGET_FRAME_DURATION = 20L * NANOS_PER_MILLI; + + private final long[] frameDurations = new long[10]; + private long totalElapsed; + private long nextFrameTarget; + private int frameIndex = 0; + private long frameStart = 0L; + + public FrameClock() { + this.totalElapsed = System.nanoTime(); + this.nextFrameTarget = System.nanoTime(); + } + + /** + * @return how long to sleep until the next frame, in milliseconds + */ + public long finishFrame() { + final long now = System.nanoTime(); + final long frameDuration = now - this.frameStart; + this.frameStart = now; + + if (frameDuration > (-5 * NANOS_PER_SECOND) && frameDuration < (5 * NANOS_PER_SECOND)) { + this.frameDurations[this.frameIndex] = frameDuration; + this.frameIndex = (this.frameIndex + 1) % this.frameDurations.length; + } + + final int lastFrameIndex = (this.frameIndex + (this.frameDurations.length - 1)) % this.frameDurations.length; + this.totalElapsed += this.frameDurations[lastFrameIndex]; + + return this.totalElapsed >= this.nextFrameTarget + ? 0L // we’re over our budget! + : (this.nextFrameTarget - this.totalElapsed) / NANOS_PER_MILLI; + } + + public int advanceFrame() { + if (this.totalElapsed < this.nextFrameTarget) { + this.frameStart += this.nextFrameTarget - this.totalElapsed; + this.totalElapsed = this.nextFrameTarget; + this.nextFrameTarget += TARGET_FRAME_DURATION; + return 1; + } else { + int framesAdvanced = 0; + + do { + ++framesAdvanced; + this.nextFrameTarget += TARGET_FRAME_DURATION; + } while (framesAdvanced < 10 && this.nextFrameTarget < this.totalElapsed); + + if (this.totalElapsed > this.nextFrameTarget) { + this.nextFrameTarget = this.totalElapsed; + } + + return framesAdvanced; + } + } + + public void reset() { + if (this.nextFrameTarget > this.totalElapsed) { + this.totalElapsed = this.nextFrameTarget; + } + + this.frameStart = 0L; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/GameUI.java b/src/main/java/funorb/shatteredplans/client/GameUI.java new file mode 100644 index 0000000..a0b4db3 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/GameUI.java @@ -0,0 +1,3269 @@ +package funorb.shatteredplans.client; + +import funorb.Strings; +import funorb.awt.KeyState; +import funorb.awt.MouseState; +import funorb.client.JagexBaseApplet; +import funorb.client.lobby.Component; +import funorb.client.lobby.ScrollPane; +import funorb.graphics.ArgbSprite; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.graphics.Rect; +import funorb.graphics.Sprite; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.game.AbstractGameView; +import funorb.shatteredplans.client.game.AbstractGameView.SystemHighlight; +import funorb.shatteredplans.client.game.ClientGameSession; +import funorb.shatteredplans.client.game.GameView; +import funorb.shatteredplans.client.game.PlayerStats; +import funorb.shatteredplans.client.game.TutorialState; +import funorb.shatteredplans.client.ui.Button; +import funorb.shatteredplans.client.ui.ChatMessage; +import funorb.shatteredplans.client.ui.DiplomacyPanelState; +import funorb.shatteredplans.client.ui.FixedPanel; +import funorb.shatteredplans.client.ui.FloatingPanel; +import funorb.shatteredplans.client.ui.Icon; +import funorb.shatteredplans.client.ui.Label; +import funorb.shatteredplans.client.ui.MultilineLabel; +import funorb.shatteredplans.client.ui.PanelState; +import funorb.shatteredplans.client.ui.ProductionPanelState; +import funorb.shatteredplans.client.ui.ProjectsPanelState; +import funorb.shatteredplans.client.ui.RoundedRect; +import funorb.shatteredplans.client.ui.ScrollBar; +import funorb.shatteredplans.client.ui.ScrollView; +import funorb.shatteredplans.client.ui.StatusPanelState; +import funorb.shatteredplans.client.ui.UIComponent; +import funorb.shatteredplans.client.ui.fe_; +import funorb.shatteredplans.client.ui.kb_; +import funorb.shatteredplans.client.ui.uc_; +import funorb.shatteredplans.game.ContiguousForce; +import funorb.shatteredplans.game.Force; +import funorb.shatteredplans.game.GameSession; +import funorb.shatteredplans.game.GameState; +import funorb.shatteredplans.game.Player; +import funorb.shatteredplans.map.CaptureAndHoldVictoryChecker; +import funorb.shatteredplans.map.ConquestVictoryChecker; +import funorb.shatteredplans.map.DerelictsVictoryChecker; +import funorb.shatteredplans.map.PointsVictoryChecker; +import funorb.shatteredplans.map.StarSystem; +import funorb.shatteredplans.map.TutorialVictoryChecker; +import funorb.shatteredplans.map.VictoryChecker; +import funorb.util.MathUtil; +import org.intellij.lang.annotations.MagicConstant; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.ListIterator; +import java.util.Queue; +import java.util.stream.IntStream; + +public final class GameUI { + public static final int INFO_PANEL_CONTENT_WIDTH = 182; + public static final int VICTORY_PANEL_ROW_HEIGHT = 56; + private static final int STATS_SCREEN_HEIGHT = 360; + private static final int STATS_SCREEN_Y = 80; + public static final int[] _hs = new int[]{-14671840, -12566464, -10461088, -8355712, -6250336, -4144960, -2039584, -1}; + public static final int[] PLAYER_COLORS_1 = new int[]{0x950e00, 0x00954d, 0x002a95, 0x820095, 0xa99700, 0x007b95, 0x7f3f3f, 0x3f7f3f, 0x3f3f7f}; + public static final int[] PLAYER_COLORS_2 = new int[]{0xff4444, 0x44ff44, 0x7777ff, 0x7f007f, 0xffff00, 0x00ffff, 0xffff00, 0x7fff7f, 0x7f7fff}; + public static final int[] PLAYER_COLORS_DARK = new int[]{0x1f0000, 0x001f00, 0x00001f, 0x1f001f, 0x1f1f00, 0x001f1f, 0x1f0f0f, 0x0f1f0f, 0x0f0f1f}; + private static final int STATS_SCREEN_OPEN_AMOUNT_MAX = 32; + private static final int STATS_GRAPH_TURN_ADVANCE_ANIMATION_COUNTER_MAX = 32; + private static final int STATS_GRAPH_MARGIN = 20; + private static final int STATS_GRAPH_WIDTH = 320; + private static final int STATS_GRAPH_HEIGHT = 220; + private static final int _rga = 56; + private static final int ADD_CHAT_MESSAGE_TIMER_MAX = 18; + + private static ArgbSprite _kbw; + public static Font _ssb; + private static Sprite _gsF; + public static Sprite READY_BUTTON; + public static int currentSettings; + public static Sprite HUD_ICON_3; + public static Sprite HUD_ICON_RED_4; + public static Sprite HUD_ICON_RED_5; + public static Sprite[] ANIM_ICONS; + private static String[] BROKEN_LINES; + public static int lastSavedSettings; + private static Queue newChatMessages; + public static Sprite FACTION_RING; + public static Sprite FACTION_RING_CENTER; + private static ChatMessage[] recentChatMessages; + private static int addChatMessageTimer; + public static boolean _gen = true; + public static Sprite[] PRODUCTION_ICONS; + private static funorb.client.lobby.ChatMessage lastChatMessage; + public static Sprite PRODUCTION_BUTTON_DOWN; + public static Sprite HUD_ICON_RED_3; + public static Sprite HUD_ICON_1; + public static Sprite HUD_ICON_2; + public static Sprite HUD_ICON_4; + public static Sprite HUD_ICON_RED_1; + public static Sprite HUD_ICON_RED_2; + public static Sprite HUD_ICON_NO_BASE_1; + public static Sprite HUD_ICON_NO_BASE_3; + public static Sprite HUD_ICON_NO_BASE_4; + public static Sprite HUD_ICON_NO_BASE_5; + public static Sprite[] ICON_CIRCLES; + public static Sprite PRODUCTION_BUTTON; + public static Sprite[] PROJECT_ICONS; + public static Sprite[] FACTION_ICONS; + public static Sprite[] FACTION_ICONS_LARGE; + public static Sprite READY_BUTTON_DOWN; + public static Sprite SHIP; + public static Sprite FACTION_RING_TAG; + private static Sprite _fjr; + public static Sprite HUD_ICON_5; + public static Sprite HUD_ICON_NO_BASE_2; + private static Sprite _ncd; + public static Sprite _R; + + private final Button systemsTabButton; + private final FixedPanel fleetsTabControl; + private final FixedPanel overviewTabControl; + private final FixedPanel _V; + private final Button overviewTabButton; + private final FixedPanel systemsTabControl; + private final FixedPanel productionTabControl; + private final int[] _p = new int[]{32, 0, 0, 0}; + private final List> statsScreenTabs; + private final int[] _ob = new int[]{82, 52, 52, 52}; + public final FixedPanel _K; + private final Button showChat; + private final Button productionTabButton; + private final List> components = new ArrayList<>(); + private final Button fleetsTabButton; + private final ArgbSprite warningSprite; + public Button animationPlayingButton; + public Button animationSpeedDoubledButton; + + private int mouseDownX; + private int mouseDownY; + private int dragOriginX; + private int dragOriginY; + private int mouseDownTicks; + private UIComponent hoveredComponent; + private UIComponent mouseDownComponent; + private UIComponent draggedComponent; + private UIComponent clickedComponent; + + private FloatingPanel victoryPanel; + private Button projectsButton; + private int statsScreenOpenAmount; + private Button victoryButton; + private Button endTurnButton; + private FloatingPanel projectsPanel; + private String turnName; + private int _x; + public Button animationAutoPlayButton; + private FixedPanel statusPanel; + private String[] playerDiplomacyStatusMessage; + private StatsScreenTab currentStatsScreenTab; + private ScrollPane> _E; + private int[][] _G; + private int newTurnPanelOpenAmount; + private int[][] _q; + private boolean isStatsScreenOpen; + private boolean _I = true; + private FloatingPanel diplomacyPanel; + private Component> _O; + private int _w; + private FloatingPanel fleetInfoPanel; + private Sprite _T; + private boolean _v = true; + private FloatingPanel productionPanel; + private String[][] _l; + /** + * The value we’re current animating {@link #statsGraphData} to. + */ + private int[][] targetStatsGraphData; + private String currentStatDescriptionTooltip; + private int _U = -1; + private int statsGraphTurnCount; + private int _jb; + private int[][] statsGraphData; + private boolean _ib; + private Button productionButton; + private Sprite _eb; + private boolean[] _z; + private int statsGraphStartTurn; + private ClientGameSession gameSession; + private int statsGraphTurnAdvanceAnimationCounter; + private Button diplomacyButton; + private Button fleetInfoButton; + private int statsGraphAlpha = 0; + + public GameUI(final ClientGameSession session) { + _fjr = new Sprite(20 + PRODUCTION_BUTTON.offsetX, PRODUCTION_BUTTON.offsetY + 20); + _kbw = new ArgbSprite(READY_BUTTON.offsetX + 20, READY_BUTTON.offsetY + 20); + this.gameSession = session; + this.productionPanel = createProductionPanel(); + this.addComponent(this.productionPanel); + if (this.gameSession.localPlayer != null) { + this.projectsPanel = createProjectsPanel(); + this.addComponent(this.projectsPanel); + } + + this.diplomacyPanel = createDiplomacyPanel(this.gameSession.gameState.playerCount); + this.initialize(); + this.addComponent(this.diplomacyPanel); + this.fleetInfoPanel = createFleetInfoPanel(this.gameSession.gameState.playerCount); + this.addComponent(this.fleetInfoPanel); + final int victoryPanelHeight = this.gameSession.gameState.victoryChecker.victoryPanelHeight(); + if (victoryPanelHeight > 0) { + this.victoryPanel = createVictoryPanel(victoryPanelHeight); + this.addComponent(this.victoryPanel); + } + + this.statusPanel = createStatusPanel(); + this.addComponent(this.statusPanel); + if (this.gameSession.localPlayer != null) { + this.projectsButton = new Button<>(511, 25, HUD_ICON_3.width, HUD_ICON_3.height, HUD_ICON_3, null, 0, HUD_ICON_RED_3, null, 0); + this.projectsButton.tooltip = StringConstants.TOOLTIP_PROJECTS_BUTTON_SHOW; + this.addComponent(this.projectsButton); + } + + this.diplomacyButton = new Button<>(HUD_ICON_3.width / 2 + 512, 5, HUD_ICON_1.width, HUD_ICON_1.height, HUD_ICON_1, null, 0, HUD_ICON_RED_1, null, 0); + this.diplomacyButton.tooltip = StringConstants.TOOLTIP_DIPLOMACY_BUTTON_SHOW; + this.addComponent(this.diplomacyButton); + this.fleetInfoButton = new Button<>(513 + HUD_ICON_3.width, 25, HUD_ICON_4.width, HUD_ICON_4.height, HUD_ICON_4, null, 0, HUD_ICON_RED_4, null, 0); + this.fleetInfoButton.tooltip = StringConstants.TOOLTIP_FLEET_INFO_BUTTON_SHOW; + this.addComponent(this.fleetInfoButton); + this.productionButton = new Button<>(HUD_ICON_1.width + 514 + HUD_ICON_3.width / 2, 5, HUD_ICON_2.width, HUD_ICON_2.height, HUD_ICON_2, null, 0, HUD_ICON_RED_2, null, 0); + this.productionButton.tooltip = StringConstants.TOOLTIP_PRODUCTION_BUTTON_SHOW; + this.addComponent(this.productionButton); + if (this.victoryPanel != null) { + this.victoryButton = new Button<>(HUD_ICON_4.width + HUD_ICON_3.width + 515, 25, HUD_ICON_5.width, HUD_ICON_5.height, HUD_ICON_5, null, 0, HUD_ICON_RED_5, null, 0); + this.victoryButton.tooltip = StringConstants.TOOLTIP_VICTORY_BUTTON_SHOW; + this.addComponent(this.victoryButton); + } + + if (this.gameSession.localPlayer != null) { + this.endTurnButton = new Button<>(521 + HUD_ICON_3.width * 3, 20, READY_BUTTON.width, READY_BUTTON.height, READY_BUTTON, null, 0, READY_BUTTON_DOWN, null, 0); + this.endTurnButton.tooltip = StringConstants.TOOLTIP_END_TURN; + this.addComponent(this.endTurnButton); + } + + this._K = new FixedPanel(590, ShatteredPlansClient.SCREEN_HEIGHT - Menu.SMALL_FONT.ascent, 60, 2 * Menu.SMALL_FONT.ascent); + this.addComponent(this._K, 0); + this.animationAutoPlayButton = new Button<>(595, ShatteredPlansClient.SCREEN_HEIGHT - ANIM_ICONS[3].height, ANIM_ICONS[3].width, ANIM_ICONS[3].height, ANIM_ICONS[3], null, 0, ANIM_ICONS[0], null, 0); + if ((currentSettings & 0b100000) == 0) { + this.animationAutoPlayButton.tooltip = StringConstants.TOOLTIP_ANIM_AUTO_PLAY_IS_OFF; + } else { + this.animationAutoPlayButton.toggle(); + this.animationAutoPlayButton.tooltip = StringConstants.TOOLTIP_ANIM_AUTO_PLAY_IS_ON; + } + + this.animationPlayingButton = new Button<>(610, -ANIM_ICONS[1].height + ShatteredPlansClient.SCREEN_HEIGHT, ANIM_ICONS[1].width, ANIM_ICONS[1].height, ANIM_ICONS[1], null, 0, ANIM_ICONS[4], null, 0); + this.animationPlayingButton.tooltip = StringConstants.TOOLTIP_ANIM_CLICK_TO_PLAY; + this.animationSpeedDoubledButton = new Button<>(625, ShatteredPlansClient.SCREEN_HEIGHT - ANIM_ICONS[5].height, ANIM_ICONS[5].width, ANIM_ICONS[5].height, ANIM_ICONS[5], null, 0, ANIM_ICONS[2], null, 0); + if ((currentSettings & 0b1000000) == 0) { + this.animationSpeedDoubledButton.tooltip = StringConstants.TOOLTIP_ANIM_SPEED_IS_NORMAL; + } else { + this.animationSpeedDoubledButton.toggle(); + this.animationSpeedDoubledButton.tooltip = StringConstants.TOOLTIP_ANIM_SPEED_IS_DOUBLE; + } + + this._K.addChild(this.animationAutoPlayButton); + this._K.addChild(this.animationPlayingButton); + this._K.addChild(this.animationSpeedDoubledButton); + this._V = new FixedPanel(3, ShatteredPlansClient.SCREEN_HEIGHT, 10 + Menu.SMALL_FONT.measureLineWidth(StringConstants.TEXT_SHOW_CHAT), 2 * Menu.SMALL_FONT.ascent); + this.showChat = new Button<>(3, ShatteredPlansClient.SCREEN_HEIGHT, this._V.width, Menu.SMALL_FONT.ascent - 4, null, StringConstants.TEXT_SHOW_CHAT, Drawing.WHITE, null, StringConstants.TEXT_HIDE_CHAT, Drawing.WHITE); + this._V.addChild(this.showChat); + this.addComponent(this._V, 0); + + this.warningSprite = new ArgbSprite(GameView.WARNING.offsetX, GameView.WARNING.offsetY); + this.warningSprite.withInstalledForDrawing(() -> { + GameView.WARNING.drawTinted(0, 0, Drawing.RED); + for (int i = 0; i < this.warningSprite.pixels.length; ++i) { + if (this.warningSprite.pixels[i] != 0) { + Drawing.addPixel(i % this.warningSprite.width, i / this.warningSprite.width, Drawing.RED, 128); + this.warningSprite.pixels[i] |= 0xff000000; + } + } + }); + + if (!this.gameSession.isMultiplayer && !this.gameSession.isTutorial) { + ShatteredPlansClient.clearChatMessages(); + final Component> var6 = new Component<>(null); + var6.children = new ArrayList<>(); + this._E = new ScrollPane<>(var6, Component.LABEL_DARK_2, Component.SCROLL_BAR); + final Component> var4 = new Component<>(Component._mpa); + this._O = new Component<>(Component._cna); + this._O.setBounds(0, ShatteredPlansClient.SCREEN_HEIGHT, ShatteredPlansClient.SCREEN_WIDTH, 120); + var4.setBounds(3, 3, 634, this._O.height - 6); + this._O.addChild(var4); + var4.addChild(this._E); + final int var5 = var4.height - 5; + this._E.setBounds(5, 5, 624, var5 - 5, 15); + _gen = false; + } + + a613cq(Menu.SMALL_FONT); + this.playerDiplomacyStatusMessage = new String[this.gameSession.gameState.playerCount + 1]; + this._z = new boolean[this.gameSession.gameState.playerCount + 1]; + + this.statsScreenTabs = new ArrayList<>(); + this.fleetsTabControl = new FixedPanel(0, 410, 128, 21); + this.productionTabControl = new FixedPanel(0, 410, 128, 21); + this.systemsTabControl = new FixedPanel(0, 410, 128, 21); + this.overviewTabControl = new FixedPanel(0, 410, 128, 21); + this.statsScreenTabs.add(this.fleetsTabControl); + this.statsScreenTabs.add(this.productionTabControl); + this.statsScreenTabs.add(this.systemsTabControl); + this.statsScreenTabs.add(this.overviewTabControl); + this.fleetsTabButton = new Button<>(0, 410, 128, 21, null, StringConstants.TEXT_SHIPS.toUpperCase(), Drawing.WHITE, null, StringConstants.TEXT_SHIPS.toUpperCase(), 0x2ad0d6); + this.fleetsTabControl.addChild(this.fleetsTabButton); + this.productionTabButton = new Button<>(0, 410, 128, 21, null, StringConstants.TEXT_PRODUCTION.toUpperCase(), Drawing.WHITE, null, StringConstants.TEXT_PRODUCTION.toUpperCase(), 0x2ad0d6); + this.productionTabControl.addChild(this.productionTabButton); + this.systemsTabButton = new Button<>(0, 410, 128, 21, null, StringConstants.TEXT_SYSTEMS.toUpperCase(), Drawing.WHITE, null, StringConstants.TEXT_SYSTEMS.toUpperCase(), 0x2ad0d6); + this.systemsTabControl.addChild(this.systemsTabButton); + this.overviewTabButton = new Button<>(0, 410, 128, 21, null, StringConstants.TEXT_OVERVIEW.toUpperCase(), Drawing.WHITE, null, StringConstants.TEXT_OVERVIEW.toUpperCase(), 0x2ad0d6); + this.overviewTabControl.addChild(this.overviewTabButton); + this.fleetsTabButton.data = StatsScreenTab.FLEETS; + this.productionTabButton.data = StatsScreenTab.PRODUCTION; + this.systemsTabButton.data = StatsScreenTab.SYSTEMS; + this.overviewTabButton.data = StatsScreenTab.OVERVIEW; + this.overviewTabButton.toggle(); + + if (this.gameSession.isTutorial) { + this.productionButton.visible = false; + this.diplomacyButton.visible = false; + this.fleetInfoButton.visible = false; + this.projectsButton.visible = false; + this.victoryButton.visible = false; + this.endTurnButton.visible = false; + this._K.visible = false; + this._V.visible = false; + TutorialState.a018jr("continue", StringConstants.TUTORIAL_CONTINUE); + TutorialState.a018jr("continue2", StringConstants.TUTORIAL_CONTINUE_2); + TutorialState.a018jr("continue3", StringConstants.TUTORIAL_CONTINUE_3); + TutorialState.a018jr("continuekey", StringConstants.TUTORIAL_CONTINUE_KEY); + TutorialState.a018jr("captureAll", StringConstants.TUTORIAL_CAPTURE_ALL); + TutorialState.a018jr("exit", StringConstants.TUTORIAL_EXIT); + TutorialState._hod = this.gameSession.localPlayer; + + for (int i = 0; i < this.gameSession.gameState.playerCount; ++i) { + final Player var7 = this.gameSession.gameState.players[i]; + TutorialState.a018jr("playercol" + i, Strings.format(">", Integer.toString(var7.color2, 16))); + TutorialState.a018jr("player" + i, Strings.format("><%1>", Integer.toString(var7.color2, 16), var7.name)); + TutorialState.a018jr("playerhome" + i, Strings.format("><%1>", Integer.toString(var7.color2, 16), var7.combinedForce.getCapital().name)); + } + + TutorialState.a529lp(TutorialMessages.get("start")); + } + } + + private void addComponent(final UIComponent component) { + assert !this.components.contains(component); + this.components.add(component); + } + + private void addComponent(final UIComponent component, final int index) { + assert !this.components.contains(component); + this.components.add(index, component); + } + + private static ScrollView createVictoryPanelRow(final GameState state, + final Player[] leaders, + final int targetPoints, + final int turnsUntilVictory, + final Player player, + final int points, + final int pointsPerTurn) { + final ScrollView row = new ScrollView<>(0, 0, INFO_PANEL_CONTENT_WIDTH, VICTORY_PANEL_ROW_HEIGHT); + + final boolean isLeader = Arrays.stream(leaders).anyMatch(leader -> player == leader); + final Sprite icon = FACTION_ICONS[player.index]; + row.addChild(new RoundedRect( + icon.width / 2, + ((row.height / 2) - 4) - (Menu.SMALL_FONT.ascent / 2), + row.width - (icon.width / 2), + Menu.SMALL_FONT.ascent + 8, + isLeader ? 0x808080 : 0x202020)); + + if (state.isPlayerDefeated(player.index)) { + row.addChild(new Label( + icon.width, + (row.height / 2) - (Menu.SMALL_FONT.ascent / 2), + row.width - icon.width, + Menu.SMALL_FONT.ascent, + StringConstants.TEXT_DEFEATED.toUpperCase())); + } else { + row.addChild(new Icon( + icon.width / 2, + (row.height / 2) - (Menu.SMALL_FONT.ascent / 2) - 1, + a774er(player, points, pointsPerTurn, targetPoints))); + } + + if (isLeader && turnsUntilVictory > 0 && turnsUntilVictory <= 3) { + row.addChild(new Label(icon.width, -(Menu.SMALL_FONT.ascent / 2) + row.height / 2, -icon.width + row.width, Menu.SMALL_FONT.ascent, Strings.format(StringConstants.VICTORY_IN_X, Integer.toString(turnsUntilVictory)))); + } + + row.addChild(new Icon(0, (row.height - icon.height) / 2, icon)); + if (!state.isPlayerDefeated(player.index)) { + String tooltip; + if (points == 1) { + if (pointsPerTurn == 1) { + tooltip = StringConstants.ONE_POINT_1_PER_TURN; + } else { + tooltip = Strings.format(StringConstants.TOOLTIP_VICTORY_PANE_ONE_MANY, Integer.toString(pointsPerTurn)); + } + } else if (pointsPerTurn == 1) { + tooltip = Strings.format(StringConstants.N_POINTS_1_PER_TURN, Integer.toString(points)); + } else { + tooltip = Strings.format(StringConstants.TOOLTIP_VICTORY_PANE_MANY_MANY, Integer.toString(points), Integer.toString(pointsPerTurn)); + } + + if (isLeader && !state.hasEnded) { + tooltip = tooltip + " " + StringConstants.TOOLTIP_PROJECTED_WINNER; + } + + row.tooltip = tooltip; + + for (final UIComponent var14 : row.children) { + var14.tooltip = tooltip; + } + } + + return row; + } + + private static Sprite a774er(final Player player, int points, int pointsPerTurn, final int targetPoints) { + if (pointsPerTurn + points == 0) { + return new Sprite(1, 1); + } + + if (points > targetPoints) { + points = targetPoints; + pointsPerTurn = 0; + } + if (pointsPerTurn > targetPoints - points) { + pointsPerTurn = targetPoints - points; + } + + final int iconWidth = FACTION_ICONS[player.index].width; + int var5 = (INFO_PANEL_CONTENT_WIDTH - iconWidth) * points / targetPoints; + int var6 = (INFO_PANEL_CONTENT_WIDTH - iconWidth) * pointsPerTurn / targetPoints; + final Sprite var7 = new Sprite(var5 + var6 + iconWidth / 2, 2 + Menu.SMALL_FONT.ascent); + Drawing.saveContext(); + var7.installForDrawing(); + if (points > 0) { + var5 += iconWidth / 2; + + for (int i = 0; i < var5; ++i) { + Drawing.verticalLine(i, 0, var7.height, Drawing.alphaOver(player.color1, 0, 128 + i * 128 / var5)); + } + + if (pointsPerTurn > 0) { + final int var8 = Drawing.alphaOver(player.color1, 0x202020, 128); + + for (int i = 0; i < var6; ++i) { + Drawing.verticalLine(var5 + i, 0, var7.height, var8); + } + } + } else { + var6 += iconWidth / 2; + final int var8 = Drawing.alphaOver(player.color1, 0x202020, 128); + + for (int i = 0; var6 > i; ++i) { + Drawing.verticalLine(i, 0, var7.height, var8); + } + } + + for (int i = 0; i < var7.width - 1; ++i) { + var7.pixels[i] = Drawing.alphaOver(var7.pixels[i], 0, 128); + var7.pixels[(var7.height - 1) * var7.width + i] = Drawing.alphaOver(var7.pixels[i + (var7.height - 1) * var7.width], 0, 64); + } + + for (int i = 0; i < var7.height; ++i) { + var7.pixels[var7.width - 1 + i * var7.width] = Drawing.alphaOver(var7.pixels[i * var7.width - 1 + var7.width], 0, 128); + } + + var7.pixels[var7.height * var7.width - 1] = Drawing.alphaOver(var7.pixels[var7.height * var7.width - 1], 0, 190); + Drawing.restoreContext(); + return var7; + } + + private void processMouseInput(final Collection> components) { + this.hoveredComponent = UIComponent.findMouseTarget(components, JagexApplet.mouseX, JagexApplet.mouseY); + if (JagexApplet.mouseButtonJustClicked == MouseState.Button.LEFT) { + this.mouseDownTicks = 0; + this.mouseDownX = JagexApplet.mousePressX; + this.mouseDownY = JagexApplet.mousePressY; + this.mouseDownComponent = UIComponent.findMouseTarget(components, this.mouseDownX, this.mouseDownY); + } else if (JagexApplet.mouseButtonDown == MouseState.Button.LEFT) { + ++this.mouseDownTicks; + if (this.draggedComponent != null) { + this.draggedComponent.handleDrag(JagexApplet.mouseX, JagexApplet.mouseY, this.dragOriginX, this.dragOriginY); + return; + } + + final int dx = this.mouseDownX - JagexApplet.mouseX; + final int dy = this.mouseDownY - JagexApplet.mouseY; + if (this.mouseDownTicks > 5 && MathUtil.isEuclideanDistanceGreaterThan(dx, dy, 5) && this.mouseDownComponent != null) { + this.draggedComponent = this.mouseDownComponent; + this.dragOriginX = this.mouseDownComponent.x - this.mouseDownX; + this.dragOriginY = this.mouseDownComponent.y - this.mouseDownY; + } + } else { + if ((this.draggedComponent == null || this.mouseDownTicks < 5) && a865rr(this.mouseDownComponent, components)) { + this.clickedComponent = this.mouseDownComponent; + if (this.clickedComponent != null) { + this.clickedComponent.handleClick(JagexApplet.mouseX - this.clickedComponent.x, JagexApplet.mouseY - this.clickedComponent.y); + } + } else { + this.clickedComponent = null; + } + + this.draggedComponent = null; + this.mouseDownComponent = null; + } + } + + private static FloatingPanel createProductionPanel() { + final FloatingPanel panel = new FloatingPanel<>(0, 60, 238, 300, StringConstants.TAB_NAME_PRODUCTION.toUpperCase()); + final fe_> var0 = new fe_<>(panel.x - 16 + panel.width, 2 + panel.y, 11, 11, -1, null, "X", Drawing.RED); + var0.data = panel; + final ScrollBar scrollBar = new ScrollBar(panel.width - 20, panel.y + 20, 11, panel.height - 28); + panel.addChild(var0); + panel.addChild(scrollBar); + final ScrollView var3 = new ScrollView<>(panel.x + 9, 20 + panel.y, 209, panel.height - 28); + panel.addChild(var3); + panel.content = var3; + scrollBar.listener = var3; + final ProductionPanelState var4 = new ProductionPanelState(); + panel.state = var4; + var4.scrollBar = scrollBar; + return panel; + } + + private static FloatingPanel createProjectsPanel() { + final FloatingPanel panel = new FloatingPanel<>(250, 60, 150, 186, StringConstants.TAB_NAME_PROJECTS.toUpperCase()); + final fe_> var0 = new fe_<>(panel.x + panel.width - 16, panel.y + 2, 11, 11, -1, null, "X", Drawing.RED); + var0.data = panel; + panel.addChild(var0); + final ScrollView var1 = new ScrollView<>(9 + panel.x, 20 + panel.y, 132, 158); + panel.addChild(var1); + panel.content = var1; + panel.state = new ProjectsPanelState(); + return panel; + } + + private static FloatingPanel createDiplomacyPanel(final int playerCount) { + final FloatingPanel panel = new FloatingPanel<>(420, 60, 200, 28 + _rga * playerCount, StringConstants.TAB_NAME_DIPLOMACY.toUpperCase()); + final fe_> var2 = new fe_<>(panel.x + 200 - 16, 2 + panel.y, 11, 11, -1, null, "X", Drawing.RED); + var2.data = panel; + panel.addChild(var2); + final ScrollView var3 = new ScrollView<>(panel.x + 9, panel.y + 20, INFO_PANEL_CONTENT_WIDTH, playerCount * _rga); + panel.addChild(var3); + panel.content = var3; + panel.state = new DiplomacyPanelState(playerCount); + return panel; + } + + private static FloatingPanel createFleetInfoPanel(final int playerCount) { + final FloatingPanel panel = new FloatingPanel<>(0, -((4 + SHIP.offsetX) * playerCount) + 479 - 28, 200, (SHIP.offsetX + 4) * playerCount + 28, StringConstants.TAB_NAME_FLEET_INFO.toUpperCase()); + final fe_> var2 = new fe_<>(184 + panel.x, 2 + panel.y, 11, 11, -1, null, "X", Drawing.RED); + var2.data = panel; + panel.addChild(var2); + final ScrollView var3 = new ScrollView<>(9 + panel.x, 20 + panel.y, INFO_PANEL_CONTENT_WIDTH, (4 + SHIP.offsetX) * playerCount); + panel.addChild(var3); + panel.content = var3; + return panel; + } + + private static FloatingPanel createVictoryPanel(final int height) { + final FloatingPanel panel = new FloatingPanel<>(320, 451 - height, 200, height + 28, StringConstants.TAB_NAME_VICTORY.toUpperCase()); + final fe_> var1 = new fe_<>(panel.x + 184, panel.y + 2, 11, 11, -1, null, "X", Drawing.RED); + var1.data = panel; + panel.addChild(var1); + final ScrollView var2 = new ScrollView<>(panel.x + 9, panel.y + 20, INFO_PANEL_CONTENT_WIDTH, height); + panel.addChild(var2); + panel.content = var2; + return panel; + } + + private static FixedPanel createStatusPanel() { + final FixedPanel _goE = new FixedPanel(5, 5, 500, 45); + final StatusPanelState var1 = new StatusPanelState(); + _goE.state = var1; + final Icon var2 = new Icon(15, 10, 36, 36, null); + _goE.addChild(var2); + var1.icon = var2; + final MultilineLabel var3 = new MultilineLabel(15, 5 - (-(_goE.height / 2) + Menu.SMALL_FONT.ascent / 2), 450, Menu.SMALL_FONT.ascent, Font.HorizontalAlignment.LEFT); + final MultilineLabel var4 = new MultilineLabel(15, _goE.height - Menu.SMALL_FONT.ascent, 450, Menu.SMALL_FONT.ascent, Font.HorizontalAlignment.RIGHT); + var1.label = var3; + _goE.addChild(var3); + _goE.addChild(var4); + return _goE; + } + + public static void a893(final boolean var1) { + if (ShatteredPlansClient.lobbyBrowserTransitionCounter > 0 && ShatteredPlansClient.showYouHaveBeenKickedDialog) { + Drawing.h115(0, 0, Drawing.width, Component._tgc.y2); + Component.YOU_HAVE_BEEN_KICKED_DIALOG.b540(var1); + } + + if ((ShatteredPlansClient.ratedLobbyRoomTransitionCounter > 0 || ShatteredPlansClient.unratedLobbyRoomTransitionCounter > 0) && ShatteredPlansClient.invitePlayersDialogOpen) { + Drawing.h115(0, 0, Drawing.width, Component._tgc.y2); + ShatteredPlansClient.invitePlayersDialog.b540(var1); + } + + } + + private static Sprite a800cle(final int var0) { + final Sprite var1 = new Sprite(_ncd.width, _ncd.height); + Drawing.saveContext(); + var1.installForDrawing(); + _ncd.drawTinted2(0, 0, var0 >= 0 ? var0 : 2105376); + Drawing.restoreContext(); + return var1; + } + + private static ScrollView a318lr(final DiplomacyPanelState var0, final Player var1, final Player var3, final Player[] var4) { + final ScrollView var5 = new ScrollView<>(0, 0, INFO_PANEL_CONTENT_WIDTH, _rga); + var5.data = var3; + var0._h[var1.index >= var3.index ? var3.index + 1 : var3.index] = var5; + final kb_ var6 = new kb_(FACTION_ICONS[var3.index].width * 3 / 4, var5.height / 2 - Menu.SMALL_FONT.ascent - 1, INFO_PANEL_CONTENT_WIDTH - FACTION_ICONS[var3.index].width * 3 / 4, var3.color1, var3.name, true); + var5.addChild(var6); + final fe_ var7 = new fe_<>(3 * FACTION_ICONS[var3.index].width / 4, var5.height / 2 + 1, INFO_PANEL_CONTENT_WIDTH - 3 * FACTION_ICONS[var3.index].width / 4, Menu.SMALL_FONT.ascent, 8421504, i432md(), StringConstants.PACT_OFFER, 3375155); + var5.addChild(var7); + var0._i[var3.index < var1.index ? var3.index : var3.index - 1] = var7; + var5.tooltip = var6.tooltip = var7.tooltip = Strings.format(StringConstants.TOOLTIP_OFFER_TREATY, var3.name); + a093bg(var4.length); + final Icon var8 = new Icon(3 * FACTION_ICONS[var3.index].width / 4, 3 + var5.height / 2 + Menu.SMALL_FONT.ascent, a800cle(-1)); + var5.addChild(var8); + var8.tooltip = Strings.format(StringConstants.TOOLTIP_OFFER_TREATY, var3.name); + var0._f[var1.index >= var3.index ? 1 + var3.index : var3.index][0] = var8; + + for (int var9 = 1; var4.length - 1 > var9; ++var9) { + final Icon var10 = new Icon(FACTION_ICONS[var3.index].width + (2 + _gsF.width) * var9, var5.height / 2 + Menu.SMALL_FONT.ascent + 3, a367wm(-1)); + var5.addChild(var10); + var10.tooltip = Strings.format(StringConstants.TOOLTIP_OFFER_TREATY, var3.name); + var0._f[var3.index > var1.index ? var3.index : 1 + var3.index][var9] = var10; + } + + final Icon var11 = new Icon(0, (var5.height - FACTION_ICONS[var3.index].height) / 2, FACTION_ICONS[var3.index]); + var5.addChild(var11); + var11.tooltip = Strings.format(StringConstants.TOOLTIP_OFFER_TREATY, var3.name); + return var5; + } + + private static ScrollView a583nl(final DiplomacyPanelState var0, final Player[] var1, final Player var3) { + final ScrollView var4 = new ScrollView<>(0, 0, INFO_PANEL_CONTENT_WIDTH, _rga); + var4.data = var3; + + int var10; + for (var10 = 0; var0._h.length > var10; ++var10) { + if (var0._h[var10] == null) { + var0._h[var10] = var4; + break; + } + } + + final kb_ var6 = new kb_(3 * FACTION_ICONS[var3.index].width / 4, -(Menu.SMALL_FONT.ascent / 2) + var4.height / 2, -(3 * FACTION_ICONS[var3.index].width / 4) + INFO_PANEL_CONTENT_WIDTH, var3.color1, var3.name, true); + var4.addChild(var6); + a093bg(var1.length); + final Icon var7 = new Icon(3 * FACTION_ICONS[var3.index].width / 4, var4.height / 2 + Menu.SMALL_FONT.ascent / 2 + 3, a800cle(-1)); + var4.addChild(var7); + var0._f[var10][0] = var7; + + for (int var8 = 1; var1.length - 1 > var8; ++var8) { + final Icon var9 = new Icon(FACTION_ICONS[var3.index].width + var8 * (2 + _gsF.width), 3 + Menu.SMALL_FONT.ascent / 2 + var4.height / 2, a367wm(-1)); + var4.addChild(var9); + var0._f[var10][var8] = var9; + } + + final Icon var11 = new Icon(0, (-FACTION_ICONS[var3.index].height + var4.height) / 2, FACTION_ICONS[var3.index]); + var4.addChild(var11); + return var4; + } + + private static void a093bg(final int var1) { + final int var2 = (INFO_PANEL_CONTENT_WIDTH - FACTION_ICONS[0].width) / (var1 - 1); + _gsF = new Sprite(var2, 2); + _ncd = new Sprite(var2 + FACTION_ICONS[0].width / 4, 2); + Drawing.saveContext(); + _gsF.installForDrawing(); + Drawing.horizontalLine(0, 0, _gsF.width, 10790052); + Drawing.horizontalLine(0, 1, _gsF.width, Drawing.WHITE); + _gsF.pixels[0] = Drawing.alphaOver(_gsF.pixels[0], 0, 185); + _gsF.pixels[1] = Drawing.alphaOver(_gsF.pixels[1], 0, 220); + _gsF.pixels[var2] = Drawing.alphaOver(_gsF.pixels[var2], 0, 185); + _gsF.pixels[1 + var2] = Drawing.alphaOver(_gsF.pixels[var2 + 1], 0, 220); + _ncd.installForDrawing(); + Drawing.horizontalLine(0, 0, _ncd.width, 10790052); + Drawing.horizontalLine(0, 1, _ncd.width, Drawing.WHITE); + Drawing.restoreContext(); + + } + + private static void tickChat() { + final funorb.client.lobby.ChatMessage newLastMessage = ShatteredPlansClient.getLastChatMessage(); + if (newLastMessage != null && newLastMessage != lastChatMessage) { + addNewChatMessages(lastChatMessage); + lastChatMessage = newLastMessage; + } + + if (addChatMessageTimer < ADD_CHAT_MESSAGE_TIMER_MAX) { + ++addChatMessageTimer; + } + + if (addChatMessageTimer >= ADD_CHAT_MESSAGE_TIMER_MAX) { + addChatMessageTimer = ADD_CHAT_MESSAGE_TIMER_MAX; + final ChatMessage message = newChatMessages.poll(); + if (message != null) { + addRecentChatMessage(message); + } + } + + for (final ChatMessage message : recentChatMessages) { + if (message != null) { + message.tick(); + } + } + } + + private static void addRecentChatMessage(final ChatMessage message) { + for (int var1 = recentChatMessages.length - 1; var1 >= 1; --var1) { + recentChatMessages[var1] = recentChatMessages[var1 - 1]; + } + addChatMessageTimer = 0; + recentChatMessages[0] = message; + } + + private static ScrollView addForceToProductionPanel(final Force var1, final ProductionPanelState var2, final boolean includePlayerName) { + final ScrollView var4 = new ScrollView<>(0, 0, 209, 70); + var4.data = var1; + final Icon var5 = new Icon(40 - (-((5 + PRODUCTION_ICONS[0].width) * 4) - HUD_ICON_4.width) - 5, Menu.SMALL_FONT.ascent - 7, _fjr); + var4.addChild(var5); + String var6 = var1.getCapital().name; + if (includePlayerName) { + var6 = var6 + " (" + var1.player.name + ")"; + } + + final kb_ var7 = new kb_(0, 0, 209, var1.player.color1, var6, false); + var4.addChild(var7); + final byte var8 = 7; + final Icon var9 = new Icon(0, var8 + var7.height, 35, 35, var1.getCapital().getSprite()); + var4.addChild(var9); + final RoundedRect var10 = new RoundedRect(40, var8 + var7.height + PRODUCTION_ICONS[0].height, 4 * PRODUCTION_ICONS[0].width + 15, 35 - PRODUCTION_ICONS[0].height, 2105376); + var4.addChild(var10); + + for (int i = 0; i < GameState.NUM_RESOURCES; ++i) { + final RoundedRect var12 = new RoundedRect(i * (5 + PRODUCTION_ICONS[i].width) + 40, var7.height + var8 + PRODUCTION_ICONS[i].height / 2, PRODUCTION_ICONS[i].width, 35 - PRODUCTION_ICONS[i].height / 2, 2105376); + var4.addChild(var12); + int var13 = var1.fleetProduction + var1.surplusResources[i]; + if (var13 < 0) { + var13 = 0; + } + + final Label var14 = new Label((PRODUCTION_ICONS[i].width + 5) * i + 40, PRODUCTION_ICONS[i].height + var7.height + var8, PRODUCTION_ICONS[i].width, Menu.SMALL_FONT.ascent, Integer.toString(var13)); + var4.addChild(var14); + final Icon var15 = new Icon(40 + i * (5 + PRODUCTION_ICONS[i].width), var7.height + var8, PRODUCTION_ICONS[i]); + var4.addChild(var15); + String var16 = StringConstants.TOOLTIP_INCOME[i]; + if (var1.surplusResources[i] == 0) { + var16 = var16 + " " + StringConstants.TOOLTIP_INCOME_LIMITING; + } + + var12.tooltip = var14.tooltip = var15.tooltip = var16; + } + + final RoundedRect var19 = new RoundedRect(PRODUCTION_ICONS[0].width * 4 + 60, var8 + var7.height + PRODUCTION_ICONS[0].height / 2, HUD_ICON_4.width, -(PRODUCTION_ICONS[0].height / 2) + 35, 534312); + var4.addChild(var19); + final Label var21 = new Label(20 + 4 * PRODUCTION_ICONS[0].width + 40, PRODUCTION_ICONS[0].height + var7.height + var8, HUD_ICON_4.width, Menu.SMALL_FONT.ascent, Integer.toString(Math.max(var1.fleetProduction, 0))); + var4.addChild(var21); + final Icon var22 = new Icon(20 - (-(4 * PRODUCTION_ICONS[0].width) - 40), var8 + (var7.height - 1), HUD_ICON_4); + var4.addChild(var22); + var19.tooltip = var21.tooltip = var22.tooltip = StringConstants.TOOLTIP_TOTAL_FLEET_PRODUCTION; + final Label var23 = new Label(54 + PRODUCTION_ICONS[0].width * 4, var7.height + var8 + PRODUCTION_ICONS[0].height, "="); + var4.addChild(var23); + final Button var24 = new Button<>(4 * PRODUCTION_ICONS[0].width + 20 + 40 - (-5 - HUD_ICON_4.width), var7.height + 3, PRODUCTION_BUTTON.width, PRODUCTION_BUTTON.height, PRODUCTION_BUTTON, null, -1, PRODUCTION_BUTTON_DOWN, null, -1); + var24.data = var1; + var4.addChild(var24); + final Label var17 = new Label(var24.x, 29 + var24.y, var24.width, Menu.SMALL_FONT.ascent, Integer.toString(var1.fleetsAvailableToBuild)); + var17.data = var1; + var4.addChild(var17); + var24.tooltip = var17.tooltip = StringConstants.TOOLTIP_PLACE_FLEETS + " " + (var1.fleetsAvailableToBuild != 1 ? Strings.format(StringConstants.TOOLTIP_FLEETS_REMAINING, Integer.toString(var1.fleetsAvailableToBuild)) : StringConstants.TOOLTIP_ONE_FLEET_REMAINING); + + var2.buildFleetsButtons.add(var24); + var2._f.add(var4); + var2.buildFleetsLabels.add(var17); + + return var4; + } + + private static Sprite a367wm(final int var0) { + final Sprite var2 = new Sprite(_gsF.width, _gsF.height); + Drawing.saveContext(); + var2.installForDrawing(); + _gsF.drawTinted2(0, 0, var0 < 0 ? 2105376 : var0); + Drawing.restoreContext(); + return var2; + } + + private static ScrollView a755bp(final int var0, final Player var1, final int var2) { + final ScrollView var3 = new ScrollView<>(0, 0, INFO_PANEL_CONTENT_WIDTH, SHIP.offsetX + 4); + final uc_ var4 = new uc_(var3.height / 2 - 3, var2, var1.color1); + var3.addChild(var4); + final Icon var5 = new Icon(-(var1._v.offsetX / 2) + var2, -(var1._v.offsetY / 2) + var3.height / 2, var1._v); + var3.addChild(var5); + final Label var6 = new Label(-(var1._v.offsetX / 2) + var2, var3.height / 2 - Menu.SMALL_FONT.ascent / 2, var1._v.offsetX, Menu.SMALL_FONT.ascent, Integer.toString(var0)); + var3.addChild(var6); + return var3; + } + + private static void a898am(final int var0, int var1, final Sprite var2, int var4, final int var5) { + int var3 = 0; + var1 -= var2.y; + var3 -= var2.x; + int var6 = var1 * var2.width + var3; + int var8 = Drawing.width * var5 + var0; + + while (true) { + --var4; + if (var4 < 0) { + return; + } + + Drawing.screenBuffer[var8++] = var2.pixels[var6++]; + } + } + + private static ScrollView a278an(final Force var2, final boolean includePlayerName) { + final ScrollView var3 = new ScrollView<>(0, 0, 209, 50); + var3.data = var2; + String var4 = var2.getCapital().name; + if (includePlayerName) { + var4 = var4 + " (" + var2.player.name + ")"; + } + + final kb_ var5 = new kb_(0, 0, 209, var2.player.color1, var4, false); + var3.addChild(var5); + + for (int var6 = 0; var6 < 4; ++var6) { + final Icon var7 = new Icon(40 + var6 * (5 + ICON_CIRCLES[var6].width), var5.height + 7, ICON_CIRCLES[var6]); + var3.addChild(var7); + int var8 = var2.fleetProduction + var2.surplusResources[var6]; + if (var8 < 0) { + var8 = 0; + } + + final Label var9 = new Label(40 + var6 * (ICON_CIRCLES[var6].width + 5), 7 + var5.height + ICON_CIRCLES[var6].height / 8, ICON_CIRCLES[var6].width, ICON_CIRCLES[var6].height, Integer.toString(var8)); + var3.addChild(var9); + var7.tooltip = var9.tooltip = StringConstants.TOOLTIP_INCOME[var6]; + } + + final RoundedRect var10 = new RoundedRect(HUD_ICON_4.width / 2 + (ICON_CIRCLES[0].width + 5) * 4 + 40, 6 + var5.height, HUD_ICON_4.width * 2, HUD_ICON_4.height - 2, 534312); + var3.addChild(var10); + int var11 = var2.fleetProduction; + if (var11 < 0) { + var11 = 0; + } + + final Label var12 = new Label(HUD_ICON_4.width + 4 * (5 + ICON_CIRCLES[0].width) + 40, var5.height + 7 + ICON_CIRCLES[0].height / 8, 3 * HUD_ICON_4.width / 2, HUD_ICON_4.height, Integer.toString(var11)); + var3.addChild(var12); + final Icon var13 = new Icon(40 + 4 * (ICON_CIRCLES[0].width + 5), 5 + var5.height, HUD_ICON_4); + var3.addChild(var13); + var10.tooltip = var12.tooltip = var13.tooltip = StringConstants.TOOLTIP_TOTAL_FLEET_PRODUCTION; + return var3; + } + + private static ScrollView a301e(final int var0, final int var1, final ProjectsPanelState var2) { + final ScrollView var3 = new ScrollView<>(0, 0, 132, 40); + var2._c[var1] = var3; + final Label var4 = new Label(132 - Menu.SMALL_FONT.measureLineWidth(StringConstants.PROJECT_NAMES[var1]), 0, StringConstants.PROJECT_NAMES[var1]); + var3.addChild(var4); + final RoundedRect var5 = new RoundedRect(PROJECT_ICONS[var1].width / 2, Menu.SMALL_FONT.ascent + 2, 132 - PROJECT_ICONS[var1].width / 2, PROJECT_ICONS[var1].height, 2105376); + var3.addChild(var5); + final Icon var6 = new Icon(3 * PROJECT_ICONS[var1].width / 4, Menu.SMALL_FONT.ascent + 5, a919ec(var1, var0)); + var3.addChild(var6); + final Icon var7 = new Icon(0, 2 + Menu.SMALL_FONT.ascent, PROJECT_ICONS[var1]); + var3.addChild(var7); + if (var0 == 5) { + final Label var8 = new Label(PROJECT_ICONS[var1].width, 1 + Menu.SMALL_FONT.ascent + 2 + PROJECT_ICONS[var1].height / 8, 130 - PROJECT_ICONS[var1].width, PROJECT_ICONS[var1].height, StringConstants.TEXT_READY); + var3.addChild(var8); + var2.statusLabels[var1] = var8; + var3.tooltip = var4.tooltip = var5.tooltip = var6.tooltip = var7.tooltip = var8.tooltip = StringConstants.TOOLTIP_PROJECT_COMPLETE; + } else { + var3.tooltip = var4.tooltip = var5.tooltip = var6.tooltip = var7.tooltip = Strings.format(StringConstants.TOOLTIP_PARTIALLY_COMPLETE, Integer.toString(var0)); + } + + return var3; + } + + private static Sprite a919ec(final int var0, final int var1) { + int var2 = (-(3 * PROJECT_ICONS[var0].width / 4) + 130) * var1 / 5; + if (var2 <= 0) { + var2 = 1; + } + + final Sprite var3 = new Sprite(var2, PROJECT_ICONS[var0].height - 6); + Drawing.saveContext(); + var3.installForDrawing(); + + int var4; + for (var4 = 0; var3.width > var4; ++var4) { + Drawing.verticalLine(var4, 0, var3.height, Drawing.alphaOver(GameView.RESOURCE_COLORS[var0], 0, 128 + 128 * var4 / var3.width)); + } + + for (var4 = 0; var3.width - 1 > var4; ++var4) { + var3.pixels[var4] = Drawing.alphaOver(var3.pixels[var4], 0, 128); + var3.pixels[var3.width * (var3.height - 1) + var4] = Drawing.alphaOver(var3.pixels[var3.width * (var3.height - 1) + var4], 0, 64); + } + + for (var4 = 0; var4 < var3.height; ++var4) { + var3.pixels[var3.width - 1 + var4 * var3.width] = Drawing.alphaOver(var3.pixels[var4 * var3.width + (var3.width - 1)], 0, 128); + } + + var3.pixels[var3.width * var3.height - 1] = Drawing.alphaOver(var3.pixels[var3.height * var3.width - 1], 0, 190); + Drawing.restoreContext(); + return var3; + } + + private static void a613cq(final Font var0) { + _ssb = var0; + lastChatMessage = ShatteredPlansClient.getLastChatMessage(); + newChatMessages = new ArrayDeque<>(); + recentChatMessages = new ChatMessage[7]; + } + + private static ScrollView a179hc(final int var0, final int var1) { + final ScrollView var2 = new ScrollView<>(var0, var1, 209, Menu.SMALL_FONT.ascent); + final int var3 = (-Menu.SMALL_FONT.measureLineWidth(StringConstants.TEXT_ENEMY_PRODUCTION) + 209 - 20) / 2; + final Sprite _vcb = new Sprite(var3, 2); + Drawing.saveContext(); + _vcb.installForDrawing(); + Drawing.fillRect(0, 0, var3, 2, Drawing.WHITE); + Drawing.restoreContext(); + final Icon var5 = new Icon(5 + var0, var2.height / 2 + var1, _vcb); + final Icon var6 = new Icon(-_vcb.width + var2.width + (var0 - 5), var2.height / 2 + var1, _vcb); + final Label var7 = new Label(var0, var1, var2.width, var2.height, StringConstants.TEXT_ENEMY_PRODUCTION); + var2.addChild(var5); + var2.addChild(var6); + var2.addChild(var7); + return var2; + } + + @SuppressWarnings("SameParameterValue") + private static void a910ld(final int var0a, final int x2, final int var2a, final int y2, final int var4a, final int alpha, final Sprite sprite) { + final int x1 = var4a - sprite.x; + final int y1 = var0a - sprite.y; + final int alpha2 = 256 - alpha; + + int j = x1 + sprite.width * y1; + int k = x2 + Drawing.width * y2; + for (int i = var2a - 1; i >= 0; --i) { + final int color1 = sprite.pixels[j++]; + final int color2 = Drawing.screenBuffer[k]; + final int rb1 = color1 & 0xff00ff; + final int g1 = color1 & 0x00ff00; + final int rb2 = color2 & 0xff00ff; + final int g2 = color2 & 0x00ff00; + final int rb3 = ((rb1 * alpha) & 0xff00ff00) + ((rb2 * alpha2) & 0xff00ff00); + final int g3 = ((g2 * alpha2) & Drawing.RED) + ((g1 * alpha) & Drawing.RED); + final int color3 = (g3 | rb3) >>> 8; + Drawing.screenBuffer[k++] = color3; + } + } + + private static boolean a865rr(final UIComponent var0, final Collection> var1) { + return var1.stream().anyMatch(var2 -> var2.hasChild(var0)); + } + + private static void a771ml(final int var0, int var1, int var2, final int var3, final Sprite var4) { + final int var5 = -var4.x; + var2 -= var4.y; + int var6 = var5 + var4.width * var2; + int var7 = Drawing.pixelIndex(var3, var0); + + while (true) { + --var1; + if (var1 < 0) { + return; + } + + int var8 = var4.pixels[var6++]; + final int var9 = Drawing.screenBuffer[var7]; + final int var10 = var8 + var9; + var8 = (var8 & 16711935) + (var9 & 16711935); + final int i = (var8 & 16777472) + (-var8 + var10 & 65536); + final int var01 = -(i >>> 8) + i; + Drawing.screenBuffer[var7++] = var01 | var10 - i; + } + } + + private static ScrollView createScrollView(final Label[] labels) { + final ScrollView view = new ScrollView<>(0, 0, INFO_PANEL_CONTENT_WIDTH, labels.length * Menu.SMALL_FONT.ascent); + + for (int i = 0; i < labels.length; ++i) { + labels[i].setPosition(0, i * Menu.SMALL_FONT.ascent); + view.addChild(labels[i]); + } + + return view; + } + + private static Sprite i432md() { + final Sprite _ssF = new Sprite(INFO_PANEL_CONTENT_WIDTH - FACTION_ICONS[0].width * 3 / 4, Menu.SMALL_FONT.ascent); + Drawing.saveContext(); + _ssF.installForDrawing(); + + int var1; + for (var1 = 1; _ssF.height - 1 > var1; ++var1) { + final int var2 = (-var1 + _ssF.height / 2) * (_ssF.height / 2 - var1); + Drawing.horizontalLine(0, var1, _ssF.width, 328965 * (_ssF.height / 2 * (_ssF.height / 2) - var2)); + } + + Drawing.horizontalLine(0, 0, _ssF.width, 1052688); + Drawing.horizontalLine(0, _ssF.height - 1, _ssF.width, 1052688); + + for (var1 = 0; var1 < _ssF.height; ++var1) { + Drawing.setPixel(_ssF.width - 1, var1, Drawing.alphaOver(_ssF.pixels[(var1 + 1) * _ssF.width - 1], 1052688, 128)); + } + + Drawing.setPixel(_ssF.width - 2, 1, Drawing.alphaOver(_ssF.pixels[_ssF.width * 2 - 2], 1052688, 128)); + Drawing.setPixel(_ssF.width - 3, 1, Drawing.alphaOver(_ssF.pixels[_ssF.width * 2 - 3], 1052688, 192)); + Drawing.setPixel(_ssF.width - 2, 2, Drawing.alphaOver(_ssF.pixels[_ssF.width * 3 - 2], 1052688, 192)); + Drawing.setPixel(_ssF.width - 2, _ssF.height - 2, Drawing.alphaOver(_ssF.pixels[_ssF.width * (_ssF.height - 1) - 2], 1052688, 128)); + Drawing.setPixel(_ssF.width - 3, _ssF.height - 2, Drawing.alphaOver(_ssF.pixels[(_ssF.height - 1) * _ssF.width - 3], 1052688, 192)); + Drawing.setPixel(_ssF.width - 2, _ssF.height - 3, Drawing.alphaOver(_ssF.pixels[_ssF.width * (_ssF.height - 2) - 2], 1052688, 192)); + Drawing.restoreContext(); + return _ssF; + } + + public static void fadeRect(int x, int y, int width, int height, final int alpha) { + if (alpha != 256) { + if (alpha == 0) { + Drawing.fillRect(x, y, width, height, 0); + } else if (alpha == 128) { + Drawing.h115(x, y, width, height); + } else { + if (x < 0) { + width += x; + x = 0; + } + + if (y < 0) { + height += y; + y = 0; + } + + if (x + width > Drawing.width) { + width = Drawing.width - x; + } + + if (height + y > Drawing.height) { + height = Drawing.height - y; + } + + --x; + final int var6 = y + height; + + for (int i = y; i < var6; ++i) { + int n = Drawing.pixelIndex(x, i); + for (int j = width; j > 0; --j) { + ++n; + final int px = Drawing.screenBuffer[n]; + final int rb = ((px & 0xff00ff) * alpha) & 0xff00ff00; + final int g = ((px & 0x00ff00) * alpha) & Drawing.RED; + Drawing.screenBuffer[n] = (g | rb) >> 8; + } + } + } + } + } + + public static String[] breakLinesWithColorTags(final Font font, final String text, final int[] lineWidths) { + if (BROKEN_LINES == null) { + BROKEN_LINES = new String[16]; + } + + int lineCount; + while (true) { + try { + lineCount = font.breakLines(text, lineWidths, BROKEN_LINES); + break; + } catch (final ArrayIndexOutOfBoundsException var6) { + if (BROKEN_LINES.length >= 1024) { + return null; + } + BROKEN_LINES = new String[BROKEN_LINES.length << 1]; + } + } + + final String[] lines = new String[lineCount]; + System.arraycopy(BROKEN_LINES, 0, lines, 0, lineCount); + fixMultilineColorTags(lines); + return lines; + } + + private static void fixMultilineColorTags(final String[] lines) { + int currentColor = -1; + for (int i = 0; i < lines.length; ++i) { + final String line = lines[i]; + if (currentColor != -1) { + lines[i] = Strings.format(">", Integer.toString(currentColor, 16)) + line; + } + + final int open = Strings.lastIndexOf(line, ""); + if (open > close) { + final int openEnd = line.indexOf('>', open); + if (openEnd != -1) { + final String colorStr = line.substring(5 + open, openEnd); + currentColor = Strings.parseHexInteger(colorStr); + } + } else if (close != -1) { + currentColor = -1; + } + } + } + + private static void addNewChatMessages(final funorb.client.lobby.ChatMessage lastOldMessage) { + int newIndex = 0; + for (int i = ShatteredPlansClient.chatMessageCount - 1; i >= 0; --i) { + if (lastOldMessage == ShatteredPlansClient.chatMessages[i]) { + newIndex = i + 1; + break; + } + } + for (int i = newIndex; i < ShatteredPlansClient.chatMessageCount; ++i) { + if (ShatteredPlansClient.chatMessages[i].component != null) { + addChatMessage(ShatteredPlansClient.chatMessages[i].component.label); + } + } + } + + private static void addChatMessage(final String text) { + final ChatMessage message = new ChatMessage(text); + if (addChatMessageTimer < ADD_CHAT_MESSAGE_TIMER_MAX) { + newChatMessages.add(message); + } else { + addRecentChatMessage(message); + } + } + + public static int breakLines(final String text, final Font font, final int[] lineWidths) { + if (BROKEN_LINES == null) { + BROKEN_LINES = new String[32]; + } + + while (true) { + try { + return font.breakLines(text, lineWidths, BROKEN_LINES); + } catch (final ArrayIndexOutOfBoundsException var6) { + if (BROKEN_LINES.length >= 1024) { + return -1; + } + BROKEN_LINES = new String[BROKEN_LINES.length << 1]; + } + } + } + + private static void d150vn() { + Drawing.withLocalContext(() -> { + Drawing.expandBoundsToInclude(0, 372, ShatteredPlansClient.SCREEN_WIDTH, ShatteredPlansClient.SCREEN_HEIGHT); + int var0 = -addChatMessageTimer + ShatteredPlansClient.SCREEN_HEIGHT; + + for (int var1 = 0; recentChatMessages.length > var1 && recentChatMessages[var1] != null; ++var1) { + recentChatMessages[var1].draw(var0); + var0 -= ADD_CHAT_MESSAGE_TIMER_MAX; + } + }); + } + + public void setPlacementMode(final PlacementMode mode) { + if (this.gameSession.placementMode == PlacementMode.BUILD_FLEET && mode != PlacementMode.BUILD_FLEET) { + this.productionPanel.state.deactivateFleetPlacement(); + } + + this.gameSession.placementMode = mode; + Arrays.fill(this.gameSession.gameView.highlightedSystems, SystemHighlight.NONE); + + ((StatusPanelState) this.statusPanel.state).icon.setSprite(null); + if (this.gameSession.gameView.animationPhase == AbstractGameView.AnimationPhase.NOT_PLAYING && !this.gameSession.readyToEndTurn) { + this.setActionHint(switch (mode) { + case MOVE_FLEET_SRC -> StringConstants.HINT_SELECT_SRC; + case MOVE_FLEET_DEST -> StringConstants.HINT_SELECT_DEST; + case DEFENSIVE_NET -> StringConstants.HINT_DEFENSEGRID; + case TERRAFORM -> StringConstants.HINT_TERRAFORM; + case STELLAR_BOMB -> StringConstants.HINT_FLARE; + case GATE_SRC -> StringConstants.HINT_SELECT_GATE_SRC; + case GATE_DEST -> StringConstants.HINT_SELECT_GATE_DEST; + case BUILD_FLEET -> Strings.format( + StringConstants.HINT_PLACEMENT, + this.gameSession.selectedForce.getCapital().name, + Integer.toString(this.gameSession.selectedForce.fleetsAvailableToBuild)); + }); + } + } + + private void activateProject(@MagicConstant(valuesFromClass = GameState.ResourceType.class) final int which) { + this.gameSession.cancelProjectOrder(which); + + if (which == GameState.ResourceType.METAL) { + this.setPlacementMode(PlacementMode.DEFENSIVE_NET); + for (final StarSystem starSystem : this.gameSession.gameState.map.systems) { + if (starSystem.owner == this.gameSession.localPlayer && !starSystem.hasDefensiveNet) { + this.gameSession.gameView.highlightedSystems[starSystem.index] = SystemHighlight.TARGET; + } + } + } else if (which == GameState.ResourceType.BIOMASS) { + this.setPlacementMode(PlacementMode.TERRAFORM); + for (final StarSystem starSystem : this.gameSession.gameState.map.systems) { + if (this.gameSession.localPlayer == starSystem.owner && starSystem.score == StarSystem.Score.NORMAL) { + this.gameSession.gameView.highlightedSystems[starSystem.index] = SystemHighlight.TARGET; + } + } + } else if (which == GameState.ResourceType.ENERGY) { + this.setPlacementMode(PlacementMode.STELLAR_BOMB); + for (final StarSystem starSystem : this.gameSession.gameState.map.systems) { + if (starSystem.owner != this.gameSession.localPlayer && (starSystem.owner == null || !this.gameSession.localPlayer.allies[starSystem.owner.index])) { + if (Arrays.stream(starSystem.neighbors).anyMatch(system -> this.gameSession.localPlayer == system.owner)) { + this.gameSession.gameView.highlightedSystems[starSystem.index] = SystemHighlight.TARGET; + } + } + } + } else if (which == GameState.ResourceType.EXOTICS) { + this.setPlacementMode(PlacementMode.GATE_SRC); + for (final StarSystem var5 : this.gameSession.gameState.map.systems) { + if (this.gameSession.localPlayer == var5.owner) { + this.gameSession.gameView.highlightedSystems[var5.index] = SystemHighlight.TARGET; + } + } + } + } + + private void updateDiplomacyState(final Player player) { + if (!this.gameSession.isTutorial || TutorialState.stage >= 6) { + final DiplomacyPanelState var3 = this.diplomacyPanel.state; + if (this.gameSession.localPlayer == null || player == this.gameSession.localPlayer) { + for (int var4 = 0; var3._f[0].length > var4; ++var4) { + final Player var5 = player.index > var4 ? this.gameSession.gameState.players[var4] : this.gameSession.gameState.players[var4 + 1]; + final int var6 = player.allies[var5.index] && !this.gameSession.gameState.isPlayerDefeated(var5.index) ? var5.color1 : -1; + if (var4 == 0) { + var3._f[0][0].setSprite(a800cle(var6)); + } else { + var3._f[0][var4].setSprite(a367wm(var6)); + } + } + } else { + final boolean var11 = player.index < this.gameSession.localPlayer.index; + final fe_ var12 = var3._i[var11 ? player.index : player.index - 1]; + final Icon[] var13 = var3._f[var11 ? 1 + player.index : player.index]; + final ScrollView var7 = var3._h[!var11 ? player.index : 1 + player.index]; + if (this.gameSession.gameState.isPlayerDefeated(player.index)) { + final String var14 = (this.gameSession.gameState.didPlayerResign(player.index)) ? StringConstants.TEXT_RESIGNED : StringConstants.TEXT_DEFEATED; + var12.a290(0, var14); + var13[0].setSprite(a800cle(-1)); + + for (int var15 = 1; var15 < var13.length; ++var15) { + var13[var15].setSprite(a367wm(-1)); + } + + var7.tooltip = null; + + for (final UIComponent var9 : var7.children) { + var9.tooltip = null; + } + } else { + int var8 = -1; + if (player.allies[this.gameSession.localPlayer.index]) { + var8 = this.gameSession.localPlayer.color1; + var12.a290(9386040, Strings.format(StringConstants.PACT_EXPIRES, Integer.toString(player.pactTurnsRemaining[this.gameSession.localPlayer.index]))); + var7.tooltip = null; + + for (final UIComponent var9 : var7.children) { + var9.tooltip = null; + } + } else if (player.hasPactOfferFrom(this.gameSession.localPlayer)) { + var12.a290(0x338033, StringConstants.PACT_AWAITING); + var7.tooltip = Strings.format(StringConstants.TOOLTIP_WAIT_TREATY, player.name); + + for (final UIComponent var9 : var7.children) { + var9.tooltip = Strings.format(StringConstants.TOOLTIP_WAIT_TREATY, player.name); + } + } else if (this.gameSession.localPlayer.hasPactOfferFrom(player)) { + var12.a290(0x338033, StringConstants.PACT_ACCEPT); + var7.tooltip = Strings.format(StringConstants.TOOLTIP_ACCEPT_TREATY, player.name); + + for (final UIComponent var9 : var7.children) { + var9.tooltip = Strings.format(StringConstants.TOOLTIP_ACCEPT_TREATY, player.name); + } + } else { + var12.a290(0x338033, StringConstants.PACT_OFFER); + var7.tooltip = Strings.format(StringConstants.TOOLTIP_OFFER_TREATY, player.name); + + for (final UIComponent var9 : var7.children) { + var9.tooltip = Strings.format(StringConstants.TOOLTIP_OFFER_TREATY, player.name); + } + } + + var13[0].setSprite(a800cle(var8)); + + for (int var15 = 1; var13.length > var15; ++var15) { + int var10 = var15 - 1; + if (this.gameSession.localPlayer.index <= var10) { + ++var10; + } + + if (var10 >= player.index) { + ++var10; + if (var10 == this.gameSession.localPlayer.index) { + ++var10; + } + } + + final int var16 = player.allies[var10] ? this.gameSession.gameState.players[var10].color1 : -1; + var13[var15].setSprite(a367wm(var16)); + } + } + } + } + } + + public void a950(final String var1, final boolean var2) { + if (var1.startsWith("production")) { + this.productionButton.visible = var2; + } + + if (var1.startsWith("projects")) { + this.projectsButton.visible = var2; + } + + if (var1.startsWith("fleets")) { + this.fleetInfoButton.visible = var2; + } + + if (var1.startsWith("diplomacy")) { + this.diplomacyButton.visible = var2; + } + + if (var1.startsWith("victory") && this.victoryButton != null) { + this.victoryButton.visible = var2; + } + + if (var1.startsWith("turn")) { + this.endTurnButton.visible = var2; + } + } + + private void drawStatsScreen() { + final int openAmount = Math.min(this.statsScreenOpenAmount, STATS_SCREEN_OPEN_AMOUNT_MAX); + final int width = MathUtil.ease(openAmount, STATS_SCREEN_OPEN_AMOUNT_MAX, 20, 550); + fadeRect(0, 0, ShatteredPlansClient.SCREEN_WIDTH, ShatteredPlansClient.SCREEN_HEIGHT, 192 + (STATS_SCREEN_OPEN_AMOUNT_MAX - openAmount << 6) / STATS_SCREEN_OPEN_AMOUNT_MAX); + final int statsX = (ShatteredPlansClient.SCREEN_WIDTH - width) / 2; + if (ShatteredPlansClient.renderQuality.statsScreenFadeQuality == RenderQuality.Level.HIGH) { + fadeRect(statsX, STATS_SCREEN_Y, width, STATS_SCREEN_HEIGHT, (STATS_SCREEN_OPEN_AMOUNT_MAX - openAmount << 7) / STATS_SCREEN_OPEN_AMOUNT_MAX + 128); + final Sprite var8 = Menu.captureScreenRect(statsX, STATS_SCREEN_Y, width, STATS_SCREEN_HEIGHT); + assert var8 != null; + Drawing.saveContext(); + var8.installForDrawing(); + Drawing.b669(3, 3, width, STATS_SCREEN_HEIGHT); + Drawing.restoreContext(); + var8.draw(statsX, STATS_SCREEN_Y, (openAmount << 7) / STATS_SCREEN_OPEN_AMOUNT_MAX); + } else if (ShatteredPlansClient.renderQuality.statsScreenFadeQuality == RenderQuality.Level.MEDIUM) { + fadeRect(statsX, STATS_SCREEN_Y, width, STATS_SCREEN_HEIGHT, 128 + (STATS_SCREEN_OPEN_AMOUNT_MAX - openAmount << 7) / STATS_SCREEN_OPEN_AMOUNT_MAX); + } else if (ShatteredPlansClient.renderQuality.statsScreenFadeQuality == RenderQuality.Level.LOW) { + if (openAmount == STATS_SCREEN_OPEN_AMOUNT_MAX) { + Drawing.fillRect(statsX, STATS_SCREEN_Y, width, STATS_SCREEN_HEIGHT, 0x0d0d14); + } else { + Drawing.fillRect(statsX, STATS_SCREEN_Y, width, STATS_SCREEN_HEIGHT, 0x0d0d14, (openAmount << 8) / STATS_SCREEN_OPEN_AMOUNT_MAX); + } + } + + Menu.drawShine(statsX, STATS_SCREEN_Y, width, STATS_SCREEN_HEIGHT); + final int[] bounds = new int[4]; + Drawing.saveBoundsTo(bounds); + Drawing.setBounds(statsX, STATS_SCREEN_Y, statsX + width, STATS_SCREEN_Y + STATS_SCREEN_HEIGHT); + boolean isVictor = false; + boolean isDefeated = false; + final boolean hasEnded = this.gameSession.gameState.hasEnded; + final boolean isDraw = hasEnded && this.gameSession.gameState.winnerIndex < 0; + if (this.gameSession.localPlayer != null) { + isVictor = this.gameSession.localPlayer.index == this.gameSession.gameState.winnerIndex; + isDefeated = this.gameSession.gameState.isPlayerDefeated(this.gameSession.localPlayer.index) || this.gameSession.gameState.victoryChecker.isLoser(this.gameSession.localPlayer); + } + + final Sprite endSprite = !isDefeated ? ShatteredPlansClient.WIN_SPRITE : ShatteredPlansClient.LOSE_SPRITE; + final int playerCount = this.gameSession.gameState.playerCount; + final int[][] graphData = this.getAnimatedStatsGraphData(); + if (this.statsGraphAlpha == 0 || graphData == null) { + for (int i = 0; i < 240; ++i) { + final int var19 = STATS_SCREEN_Y + STATS_GRAPH_MARGIN + i; + final int var20 = STATS_GRAPH_MARGIN + statsX; + final int var21 = Math.min(width - 40, 320); + if (var21 >= 0) { + a898am(var20, i, endSprite, var21, var19); + Drawing.setPixel(var20 - 1, var19, Drawing.WHITE); + Drawing.setPixel(var20 + var21, var19, Drawing.WHITE); + } + } + } else { + for (int i = 0; i < 240; ++i) { + final int var19 = i + STATS_GRAPH_MARGIN + STATS_SCREEN_Y; + final int var20 = STATS_GRAPH_MARGIN + statsX; + final int var21 = Math.min(width - (STATS_GRAPH_MARGIN * 2), 320); + if (var21 >= 0) { + a771ml(var19, var21, i, var20, endSprite); + Drawing.horizontalLine(var20, var19, var21, 0, 192); + Drawing.setPixel(var20 - 1, var19, Drawing.WHITE); + Drawing.setPixel(var20 + var21, var19, Drawing.WHITE); + } + } + } + + if (this.statsGraphAlpha != 0 && this.statsGraphAlpha != 25 && graphData != null) { + for (int i = 0; i < 240; ++i) { + final int var19 = i + STATS_SCREEN_Y + STATS_GRAPH_MARGIN; + final int var20 = statsX + STATS_GRAPH_MARGIN; + final int var21 = Math.min(width - 40, STATS_GRAPH_WIDTH); + if (var21 >= 0) { + a910ld(i, var20, var21, var19, 0, 256 - this.statsGraphAlpha, endSprite); + } + } + } + + Drawing.horizontalLine(statsX + STATS_GRAPH_MARGIN - 1, 99, STATS_GRAPH_WIDTH + 2, Drawing.WHITE); + Drawing.horizontalLine(statsX + STATS_GRAPH_MARGIN - 1, 340, STATS_GRAPH_WIDTH + 2, Drawing.WHITE); + final int var18 = statsX + STATS_GRAPH_WIDTH + 125; + String endMessage = isVictor ? StringConstants.TEXT_VICTORY + : isDefeated ? StringConstants.TEXT_DEFEAT + : isDraw ? StringConstants.TEXT_PEACE_SHORT + : hasEnded ? StringConstants.TEXT_VICTORY + : null; + if (this.gameSession.localPlayer == null && !isDraw) { + endMessage = " "; + } + + Menu.FONT.drawCentered(endMessage, var18, 107, Drawing.WHITE); + final int var21 = 40 + statsX - 10 + 320; + int var43 = 120; + int var23 = this.currentStatsScreenTab.ordinal() * 4; + + for (int var24 = 0; var24 < 4; ++var24) { + this.b050(var24, var43, var21, var23); + ++var23; + var43 += 8 + this._ob[var24]; + } + + final int var17 = Math.min(width - 40, 320); + Drawing.setBounds(20 + statsX, 100, var17 + statsX + 20, 340); + if (this.statsGraphAlpha != 0 && graphData != null) { + final int turnCount = graphData[0].length; + int graphMax = 1; + for (int i = 0; i < playerCount; ++i) { + for (int j = 0; j < turnCount; ++j) { + if (graphMax < graphData[i][j]) { + graphMax = graphData[i][j]; + } + } + } + + final int graphHeight = STATS_GRAPH_HEIGHT + 2; + final int graphWidth = STATS_GRAPH_WIDTH + 2; + final int graphX = statsX + STATS_GRAPH_MARGIN; + final int graphSteps; + if (this.statsGraphTurnAdvanceAnimationCounter == 0) { + graphSteps = this.statsGraphTurnCount - 1 << 10; + } else { + graphSteps = MathUtil.ease(this.statsGraphTurnAdvanceAnimationCounter, STATS_GRAPH_TURN_ADVANCE_ANIMATION_COUNTER_MAX, this.statsGraphStartTurn << 10, this.statsGraphTurnCount << 10) - 1024; + } + + if (this.statsGraphAlpha == 256) { + for (int i = 0; i < playerCount; ++i) { + final int color = this.gameSession.gameState.players[i].color2; + int x1 = graphX; + int y1 = graphWidth - (graphHeight * graphData[i][0] / graphMax); + int y1a = y1; + + for (int j = 1; j < turnCount; ++j) { + final int x2 = graphX + (((j * STATS_GRAPH_WIDTH) << 10) / graphSteps); + final int y2 = graphWidth - (graphHeight * graphData[i][j] / graphMax); + + for (int k = 0; k < x2 - x1; ++k) { + final int y2a = MathUtil.ease(k, x2 - x1, y1, y2); + Drawing.line(x1 + k - 1, y1a, x1 + k, y2a, color); + y1a = y2a; + } + + x1 = x2; + y1 = y2; + } + } + } else { + for (int i = 0; i < playerCount; ++i) { + final int color = this.gameSession.gameState.players[i].color2; + int x1 = graphX; + int y1 = graphWidth - (graphHeight * graphData[i][0] / graphMax); + int y1a = y1; + + for (int j = 1; j < turnCount; ++j) { + final int x2 = graphX + (((j * STATS_GRAPH_WIDTH) << 10) / graphSteps); + final int y2 = graphWidth - (graphHeight * graphData[i][j] / graphMax); + + for (int k = 0; k < x2 - x1; ++k) { + final int y2a = MathUtil.ease(k, x2 - x1, y1, y2); + Drawing.line(x1 + k - 1, y1a, x1 + k, y2a, color, this.statsGraphAlpha); + y1a = y2a; + } + + x1 = x2; + y1 = y2; + } + } + } + + int var30 = (turnCount + 7) / 8; + if (var30 == 0) { + var30 = 1; + } + + for (int i = 0; i < turnCount; ++i) { + final int x1 = graphX + STATS_GRAPH_WIDTH * i / (turnCount - 1); + if (i % var30 == 0) { + final String var47 = Integer.toString(i); + final int var34 = Menu.SMALL_FONT.measureLineWidth(var47); + int var35 = -(var34 >> 1) + x1; + if (i == 0) { + var35 = graphX + var34 / 2; + } else if (turnCount - 1 == i) { + var35 -= var34; + } + + Menu.SMALL_FONT.draw(Integer.toString(i), var35, 20 + STATS_SCREEN_Y + graphHeight + Menu.SMALL_FONT.ascent, Drawing.WHITE); + } + + Drawing.verticalLineBlended(x1, 100, 222, 0x0c0c0c); + } + } + + Drawing.setBounds(statsX, STATS_SCREEN_Y, statsX + width, 440); + if (this.gameSession.gameState.hasEnded || this.gameSession.localPlayer != null && this.gameSession.gameState.isPlayerDefeated(this.gameSession.localPlayer.index)) { + Menu.SMALL_FONT.drawCentered(StringConstants.TEXT_ESC_TO_EXIT, statsX + 20 + 160, 366, Drawing.WHITE); + } + + this.statsScreenTabs.forEach(UIComponent::draw); + + Drawing.restoreBoundsFrom(bounds); + if (this.currentStatDescriptionTooltip != null && this._jb > 60) { + this.a209(this.currentStatDescriptionTooltip); + } + } + + private void b050(final int var1, final int var2, final int var3, final int var5) { + final int var6 = this.gameSession.gameState.playerCount; + final int var7 = this._G[var5][var6 - 1]; + int var8 = this._G[var5][var6 - 2]; + if (this.gameSession.localPlayer != null && this.gameSession.localPlayer.index != var7) { + var8 = this.gameSession.localPlayer.index; + } + + final int var9 = this._ob[var1]; + + Menu.drawShine(var3, var2, 190, var9); + Menu.SMALL_FONT.draw(ShatteredPlansClient.STAT_NAMES[var5], 10 + var3, var2 + Menu.SMALL_FONT.ascent, Drawing.WHITE); + final short var10 = 210; + final int var11 = var10 / (6 + var6); + final int var12 = 2 * var11 + 12; + final int var13 = -(var11 * 8) + var10; + final int var14 = var9 - 27; + if (this._p[var1] == 0) { + this.a050(var7, var5, var3 + 10, Menu.SMALL_FONT.ascent + var2 + (var14 >> 1)); + this.a050(var8, var5, var3 + 10, var2 - (-Menu.SMALL_FONT.ascent - var14)); + } else { + final int[] var15 = JagexBaseApplet.a612(this._G[var5]); + + for (int var16 = 0; var6 > var16; ++var16) { + int var17 = (var6 * var14 - (var15[var16] * var14 >> 1)) / var6; + final int var18 = (var6 - var15[var16]) * var14 / var6; + int var19 = (-var12 + this._ob[var1] << 8) / var13; + if (var16 == var7) { + var17 = var14 >> 1; + var19 = 256; + } + + if (var16 == var8) { + var17 = var14; + var19 = 256; + } + + final int var20 = Menu.SMALL_FONT.ascent + var2 + MathUtil.ease(this._p[var1], 32, var17, var18); + this.a132(var5, var20, var16, var19, 10 + var3); + } + } + + } + + public void handleVictory() { + if (this.endTurnButton != null) { + this.endTurnButton.enabled = false; + } + + this.productionPanel.visible = false; + if (this.projectsPanel != null) { + this.projectsPanel.visible = false; + } + + this.diplomacyPanel.visible = false; + this.fleetInfoPanel.visible = false; + + if (this.victoryPanel != null) { + this.victoryPanel.visible = false; + } + } + + private void a132(final int var1, final int var2, final int var3, final int var4, final int var6) { + final Player var7 = this.gameSession.gameState.players[var3]; + final int var8 = var7.color2; + Menu.SMALL_FONT.drawRightAligned(this._l[var1][var3], var6 + 27, var2, var8, var4); + Menu.SMALL_FONT.draw(StringConstants.TEXT_ORDINALS[this._q[var1][var3]], 37 + var6, var2, var8, var4); + Menu.SMALL_FONT.draw(var7.name, var6 + 67, var2, var8, var4); + } + + private void processInputStatsScreen() { + final int var2 = this.statsScreenOpenAmount; + final int var3 = Math.min(32, var2); + + final int var4 = MathUtil.ease(var3, 32, 20, 550); + final int var5 = (-var4 + ShatteredPlansClient.SCREEN_WIDTH) / 2; + final int var7 = 320 + var5 + 40 - 10; + int var8 = 131; + + int var9; + int var10; + for (var9 = 0; var9 < 4; ++var9) { + var10 = this._ob[var9]; + if (var7 <= JagexApplet.mouseX && var8 <= JagexApplet.mouseY && 190 + var7 > JagexApplet.mouseX && JagexApplet.mouseY <= var8 + var10) { + break; + } + + var8 += var10 + 8; + } + + this.processMouseInput(this.statsScreenTabs); + if (this.clickedComponent != null) { + this.selectStatsScreenTab((StatsScreenTab) this.clickedComponent.data); + if (this.fleetsTabButton.isActive()) { + this.fleetsTabButton.toggle(); + } + if (this.productionTabButton.isActive()) { + this.productionTabButton.toggle(); + } + if (this.systemsTabButton.isActive()) { + this.systemsTabButton.toggle(); + } + if (this.overviewTabButton.isActive()) { + this.overviewTabButton.toggle(); + } + ((Button) this.clickedComponent).toggle(); + } + + if (var9 == 4) { + this.currentStatDescriptionTooltip = null; + this._jb = 0; + } else { + this._w = var9; + var10 = this._w + this.currentStatsScreenTab.ordinal() * 4; + final String var14 = ShatteredPlansClient.STAT_DESCS[var10]; + //noinspection StringEquality + if (var14 == this.currentStatDescriptionTooltip) { + ++this._jb; + } else { + this.currentStatDescriptionTooltip = ShatteredPlansClient.STAT_DESCS[var10]; + this._jb = 0; + } + } + + } + + private void a050(final int var1, final int var3, final int var4, final int var5) { + final Player var6 = this.gameSession.gameState.players[var1]; + final int var7 = var6.color2; + Menu.SMALL_FONT.drawRightAligned(this._l[var3][var1], var4 + 27, var5, var7); + Menu.SMALL_FONT.draw(StringConstants.TEXT_ORDINALS[this._q[var3][var1]], var4 + 37, var5, var7); + Menu.SMALL_FONT.draw(var6.name, 67 + var4, var5, var7); + } + + public void a223(final String var1, final boolean var2) { + if (var1.startsWith("production")) { + this.productionPanel.visible = var2; + } + + if (var1.startsWith("projects")) { + this.projectsPanel.visible = var2; + } + + if (var1.startsWith("fleets")) { + this.fleetInfoPanel.visible = var2; + } + + if (var1.startsWith("diplomacy")) { + this.diplomacyPanel.visible = var2; + } + + if (var1.startsWith("victory") && this.victoryPanel != null) { + this.victoryPanel.visible = var2; + } + + } + + private void updateProjectsPanel() { + this.projectsPanel.content.removeChildren(); + this.projectsPanel.flashing = false; + this.projectsButton.deactivate(); + final ProjectsPanelState var2 = this.projectsPanel.state; + for (int i = 0; i < GameState.NUM_RESOURCES; ++i) { + final ScrollView var4 = a301e(this.gameSession.localPlayer.researchPoints[i], i, var2); + var4.setPosition(this.projectsPanel.content.x, this.projectsPanel.content.contentHeight + this.projectsPanel.content.y); + this.projectsPanel.content.addChild(var4); + if (this.gameSession.localPlayer.researchPoints[i] >= 5) { + this.projectsPanel.flashing = true; + this.projectsButton.activate(); + } + } + } + + private void b115(final int var1, final int var2, final int var4) { + final String var5 = StringConstants.TURN_OBJECTIVE.toUpperCase() + ": " + StringConstants.GAME_TYPE_TOOLTIPS[2]; + Menu.SMALL_FONT.drawParagraph(var5, var4 + 5, var2 + 5, var1 - 10, ShatteredPlansClient.SCREEN_HEIGHT, Drawing.WHITE, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, Menu.SMALL_FONT.ascent); + final int var6 = FACTION_RING.width * 2 + Menu.SMALL_FONT.measureLineWidth("= " + StringConstants.TURN_ONE_POINT); + Drawing.fillRoundedRect((var1 - var6) / 2 + (var4 - 10), 15 + var2 + Menu.SMALL_FONT.ascent, var6 + 20, 10 + FACTION_RING.height * 3, 5, 0, 128); + int var7 = 29 + Menu.SMALL_FONT.ascent + var2; + final int var8 = FACTION_RING.width + Menu.SMALL_FONT.measureLineWidth("= " + Strings.format(StringConstants.TURN_POINTS, Integer.toString(3))); + FACTION_RING_CENTER.draw((-FACTION_RING_CENTER.width + FACTION_RING.width) / 2 + (var1 - var8) / 2 + var4, var7); + FACTION_RING.draw((-var8 + var1) / 2 + var4, var7 - 9); + Drawing.drawCircleGradientAdd(Menu._emc[0] + (var4 + (FACTION_RING.width + (var1 - var8)) / 2 << 4), Menu._pmDb[0] + (var7 + FACTION_RING_CENTER.height / 2 << 4), 50, 7, _hs); + Drawing.drawCircleGradientAdd((var4 + (FACTION_RING.width + var1 - var8) / 2 << 4) + Menu._emc[2], (FACTION_RING_CENTER.height / 2 + var7 << 4) + Menu._pmDb[2], 50, 7, _hs); + Drawing.drawCircleGradientAdd(Menu._emc[3] + ((FACTION_RING.width - var8 + var1) / 2 + var4 << 4), (FACTION_RING_CENTER.height / 2 + var7 << 4) + Menu._pmDb[3], 50, 7, _hs); + Menu.SMALL_FONT.draw("= " + Strings.format(StringConstants.TURN_POINTS, Integer.toString(3)), FACTION_RING.width + var4 + (-var8 + var1) / 2 + 5, FACTION_RING.height / 2 + var7 - 4, Drawing.WHITE); + var7 += FACTION_RING.height; + FACTION_RING_CENTER.draw(var4 + (-var8 + var1) / 2 + (-FACTION_RING_CENTER.width + FACTION_RING.width) / 2, var7); + FACTION_RING.draw((var1 - var8) / 2 + var4, var7 - 9); + Drawing.drawCircleGradientAdd((var4 + (FACTION_RING.width - var8 + var1) / 2 << 4) + Menu._emc[0], Menu._pmDb[0] + (FACTION_RING_CENTER.height / 2 + var7 << 4), 50, 7, _hs); + Drawing.drawCircleGradientAdd(((FACTION_RING.width - var8 + var1) / 2 + var4 << 4) + Menu._emc[1], Menu._pmDb[1] + (FACTION_RING_CENTER.height / 2 + var7 << 4), 50, 7, _hs); + Menu.SMALL_FONT.draw("= " + Strings.format(StringConstants.TURN_POINTS, Integer.toString(2)), 5 + FACTION_RING.width + (var1 - var8) / 2 + var4, var7 + FACTION_RING.height / 2 - 4, Drawing.WHITE); + var7 += FACTION_RING.height; + FACTION_RING_CENTER.draw(var4 + (-var6 + var1) / 2 + (-FACTION_RING_CENTER.width + FACTION_RING.width) / 2 - 5, var7); + FACTION_RING.draw((-var6 + var1) / 2 + var4 - 5, var7 - 9); + Drawing.drawCircleGradientAdd(Menu._emc[0] + ((FACTION_RING.width + (var1 - var6)) / 2 + var4 - 5 << 4), Menu._pmDb[0] + (var7 + FACTION_RING_CENTER.height / 2 << 4), 50, 7, _hs); + FACTION_RING_CENTER.draw(FACTION_RING.width + (-var6 + var1) / 2 + var4 - 5 + (-FACTION_RING_CENTER.width + FACTION_RING.width) / 2, var7); + FACTION_RING.draw(var4 + (-var6 + var1) / 2 + (FACTION_RING.width - 5), var7 - 9); + Menu.SMALL_FONT.draw("= " + StringConstants.TURN_ONE_POINT, 2 * FACTION_RING.width + (-var6 + var1) / 2 + var4, FACTION_RING.height / 2 + (var7 - 4), Drawing.WHITE); + } + + private void c115(final int var1, final int var3, final int var4) { + final String var5 = StringConstants.TURN_OBJECTIVE.toUpperCase() + ": " + StringConstants.GAME_TYPE_TOOLTIPS[1]; + Menu.SMALL_FONT.drawParagraph(var5, 5 + var1, var3 + 5, var4 - 10, ShatteredPlansClient.SCREEN_HEIGHT, Drawing.WHITE, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, Menu.SMALL_FONT.ascent); + final int var6 = StarSystem.PLANET_SCORCHED_EARTH.width + Menu.SMALL_FONT.measureLineWidth("= " + StringConstants.TURN_ONE_POINT); + Drawing.fillRoundedRect((var4 - var6) / 2 - 5 + var1, 20 + Menu.SMALL_FONT.ascent + var3, var6 + 15, StarSystem.PLANET_SCORCHED_EARTH.height + 10, 5, 0, 128); + StarSystem.PLANET_SCORCHED_EARTH.draw(var1 + (var4 - var6) / 2, Menu.SMALL_FONT.ascent + var3 + 20); + Menu.SMALL_FONT.draw("= " + StringConstants.TURN_ONE_POINT, (var4 - var6) / 2 + var1 + StarSystem.PLANET_SCORCHED_EARTH.width, 25 + Menu.SMALL_FONT.ascent + StarSystem.PLANET_SCORCHED_EARTH.height / 2 + var3, Drawing.WHITE); + } + + private void selectStatsScreenTab(final StatsScreenTab tab) { + final GameState state = this.gameSession.gameState; + final int playerCount = state.playerCount; + if (tab == this.currentStatsScreenTab) { + this.statsGraphData = this.targetStatsGraphData; + } else { + if (this.statsGraphTurnAdvanceAnimationCounter == 0) { + this.statsGraphData = this.targetStatsGraphData; + } else { + this.statsGraphData = this.getAnimatedStatsGraphData(); + } + this.statsGraphTurnAdvanceAnimationCounter = 1; + this.currentStatsScreenTab = tab; + } + + final int turnCount = Math.min(state.turnNumber - this.gameSession.turnNumberWhenJoined + 1, 100); + if (this.statsGraphData == null || turnCount == this.statsGraphData[0].length) { + this.statsGraphStartTurn = turnCount; + } else { + final int startTurn = this.statsGraphData[0].length; + final int len = Math.min(turnCount, startTurn); + final int offset = Math.max(startTurn - turnCount, 0); + + final int[][] statsGraphData = new int[playerCount][turnCount]; + for (int playerIndex = 0; playerIndex < playerCount; ++playerIndex) { + System.arraycopy(this.statsGraphData[playerIndex], offset, statsGraphData[playerIndex], 0, len); + for (int turnIndex = startTurn; turnIndex < turnCount; ++turnIndex) { + statsGraphData[playerIndex][turnIndex] = this.statsGraphData[playerIndex][startTurn - 1]; + } + } + + this.statsGraphTurnAdvanceAnimationCounter = 1; + this.statsGraphData = statsGraphData; + this.statsGraphStartTurn = startTurn; + } + + this.statsGraphTurnCount = turnCount; + if (turnCount > 1) { + this.targetStatsGraphData = new int[playerCount][]; + for (final Player player : state.players) { + final PlayerStats var17 = player.stats; + final int[] var18 = this.currentStatsScreenTab == StatsScreenTab.PRODUCTION ? var17.production + : this.currentStatsScreenTab == StatsScreenTab.SYSTEMS ? var17.systems + : var17.fleets; + final int[] var19 = new int[turnCount]; + for (int turnIndex = 0; turnIndex < turnCount; ++turnIndex) { + final int var14 = (1 + turnIndex + state.turnNumber + (100 - turnCount)) % 100; + var19[turnIndex] = var18[var14] << 10; + } + + this.targetStatsGraphData[player.index] = var19; + } + } else { + this.targetStatsGraphData = null; + } + } + + public void markProjectPending(@MagicConstant(valuesFromClass = GameState.ResourceType.class) final int type) { + if (this.projectsPanel.state.statusLabels[type] != null) { + this.projectsPanel.state.statusLabels[type].text = StringConstants.PENDING; + } + + final ScrollView var4 = this.projectsPanel.state._c[type]; + var4.tooltip = StringConstants.TOOLTIP_PROJECT_PENDING; + + for (final UIComponent var5 : var4.children) { + if (var5.tooltip != null) { + var5.tooltip = StringConstants.TOOLTIP_PROJECT_PENDING; + } + } + } + + private void e150() { + this.fleetInfoPanel.content.removeChildren(); + final int[] var2 = new int[this.gameSession.gameState.playerCount]; + final StarSystem[] var3 = this.gameSession.gameState.map.systems; + + int var4; + int var10001; + for (var4 = 0; var4 < var3.length; ++var4) { + final StarSystem var5 = var3[var4]; + if (var5.owner != null) { + var10001 = var5.owner.index; + var2[var10001] += var5.garrison; + } + } + + final Player[] var10 = this.gameSession.gameState.players; + + for (var4 = 0; var10.length > var4; ++var4) { + final Player var13 = var10[var4]; + if (!this.gameSession.gameState.gameOptions.unifiedTerritories) { + for (final ContiguousForce var6 : var13.contiguousForces) { + if (var6.fleetProduction > 0) { + var10001 = var13.index; + var2[var10001] += var6.fleetProduction; + } + } + } else if (var13.combinedForce.fleetProduction > 0) { + var10001 = var13.index; + var2[var10001] += var13.combinedForce.fleetProduction; + } + } + + int var11 = 0; + + int var14; + for (var14 = 0; var2.length > var14; ++var14) { + final int var16 = var2[var14]; + if (var16 > var11) { + var11 = var16; + } + } + + final Player[] var15 = this.gameSession.gameState.players; + + for (var14 = 0; var15.length > var14; ++var14) { + final Player var17 = var15[var14]; + final int var7 = var2[var17.index]; + final int var8 = var17._v.offsetX / 2 + (-var17._v.offsetX + INFO_PANEL_CONTENT_WIDTH) * var7 / var11; + final ScrollView var9 = a755bp(var7, var17, var8); + var9.setPosition(this.fleetInfoPanel.content.x, this.fleetInfoPanel.content.contentHeight + this.fleetInfoPanel.content.y); + this.fleetInfoPanel.content.addChild(var9); + } + + } + + public void handleProjectOrderCanceled(@MagicConstant(valuesFromClass = GameState.ResourceType.class) final int type) { + final ProjectsPanelState panelState = this.projectsPanel.state; + if (panelState.statusLabels[type] != null) { + panelState.statusLabels[type].text = StringConstants.TEXT_READY; + } + + final ScrollView var4 = panelState._c[type]; + var4.tooltip = StringConstants.TOOLTIP_PROJECT_COMPLETE; + + for (final UIComponent child : var4.children) { + if (child.tooltip != null) { + child.tooltip = StringConstants.TOOLTIP_PROJECT_COMPLETE; + } + } + } + + public void a735(final Player[] var1) { + final String[] var3 = new String[1 + var1.length]; + final boolean[] var4 = new boolean[var1.length + 1]; + + for (int var5 = 0; var5 < this.playerDiplomacyStatusMessage.length - 1; ++var5) { + var3[var5] = this.playerDiplomacyStatusMessage[var5]; + var4[var5] = this._z[var5]; + } + + var3[var3.length - 1] = this.playerDiplomacyStatusMessage[this.playerDiplomacyStatusMessage.length - 1]; + var4[var4.length - 1] = this._z[this._z.length - 1]; + this.playerDiplomacyStatusMessage = var3; + this._z = var4; + this.e150(); + final int var5 = this.fleetInfoPanel.height; + this.fleetInfoPanel.a183(this.fleetInfoPanel.content.contentHeight + 28, this.fleetInfoPanel.width); + this.fleetInfoPanel.content.a183(this.fleetInfoPanel.content.contentHeight + 10, this.fleetInfoPanel.content.width); + this.fleetInfoPanel.translate(0, -this.fleetInfoPanel.height + var5); + this.f150(); + this.initialize(); + final Player[] var6 = this.gameSession.gameState.players; + + for (final Player var8 : var6) { + this.updateDiplomacyState(var8); + } + + this.diplomacyPanel.a183(this.diplomacyPanel.content.contentHeight + 28, this.diplomacyPanel.width); + this.diplomacyPanel.content.a183(10 + this.diplomacyPanel.content.contentHeight, this.diplomacyPanel.content.width); + final int[][] var9 = new int[var1.length][]; + final int[][] var10 = new int[var1.length][]; + if (this.targetStatsGraphData != null) { + System.arraycopy(this.targetStatsGraphData, 0, var9, 0, this.targetStatsGraphData.length); + var9[var1.length - 1] = new int[var9[0].length]; + this.targetStatsGraphData = var9; + } + + if (this.statsGraphData != null) { + System.arraycopy(this.statsGraphData, 0, var10, 0, this.statsGraphData.length); + var10[var1.length - 1] = new int[var10[0].length]; + this.statsGraphData = var10; + } + + if (TutorialState.stage == 7) { + this.gameSession.gameState.victoryChecker = new TutorialVictoryChecker(var1); + this.gameSession.gameState.victoryChecker.updateVictoryPanel(this.gameSession.gameState, this); + } + } + + public void render() { + if (this.gameSession.isTutorial) { + TutorialState.a423mq(); + } + + if (this.gameSession.isMultiplayer && !this.gameSession.gameState.hasEnded) { + Drawing.fillRoundedRect(HUD_ICON_3.width * 3 + 521, 4, READY_BUTTON.width, Menu.SMALL_FONT.ascent - 2, 2, 0, 128); + final int var2 = (this.gameSession.turnTicksLeft + 49) / 50; + if (this.gameSession.turnTicksLeft < 0) { + Menu.SMALL_FONT.drawCentered(this.a436(Math.abs(var2)), 521 + HUD_ICON_3.width * 3 + READY_BUTTON.width / 2, Menu.SMALL_FONT.ascent * 3 / 4 + 3, Drawing.RED); + } + + if (GameSession.TURN_DURATIONS[this.gameSession.gameState.turnLengthIndex] <= 3 * this.gameSession.turnTicksLeft) { + Menu.SMALL_FONT.drawCentered(this.a436(Math.abs(var2)), READY_BUTTON.width / 2 + 3 * HUD_ICON_3.width + 521, Menu.SMALL_FONT.ascent * 3 / 4 + 3, Drawing.WHITE); + } else { + final int var3 = this.gameSession.turnTicksLeft % 50; + if (var3 >= 30 || var3 < 20 && var3 >= 10) { + Menu.SMALL_FONT.drawCentered(this.a436(Math.abs(var2)), HUD_ICON_3.width * 3 + 521 + READY_BUTTON.width / 2, 3 * Menu.SMALL_FONT.ascent / 4 + 3, 3974311); + } + } + } + + if (this.gameSession.isTutorial && TutorialState._phg) { + _kbw.draw(this.endTurnButton.x - 10, this.endTurnButton.y - 10); + } + + for (final ListIterator> it = this.components.listIterator(this.components.size()); it.hasPrevious(); ) { + final UIComponent var12 = it.previous(); + if (!(var12 instanceof FloatingPanel)) { + var12.draw(); + } + } + + d150vn(); + if (this._O != null) { + this._O.b540(false); + } + + if (this._U != -1) { + final int var4 = this._x; + final int var5 = 5 + this.statusPanel.height + this.statusPanel.y; + Drawing.fillRoundedRect(this.statusPanel.x + 1, var5, this._T.width + 10, Menu.SMALL_FONT.ascent, 5, 0); + Drawing.f669(this.statusPanel.x, var5 - 1, 12 + this._T.width, Menu.SMALL_FONT.ascent + 2, 6, 2052949); + TutorialState.a833sa(var4 * 5, this.statusPanel.x + 6, 32, this._T, var5 - 4); + if (this._ib) { + final int var6 = this._x - 125; + if (var6 > 0) { + int var7 = (var6 << 12) / 250; + var7 &= 511; + if (var7 > 256) { + var7 = 512 - var7; + } + + this._eb.drawAdd(6 + this.statusPanel.x, var5 - 4, var7); + } + } + } + + int var4 = ShatteredPlansClient.currentTick % 64; + if (var4 > 24 && var4 <= 40) { + var4 = 24; + } + if (var4 > 40) { + var4 = 64 - var4; + } + + var4 = var4 * 10; + final int var5 = Drawing.alphaOver(Drawing.RED, Drawing.WHITE, var4); + if (this.productionPanel.flashing && this.productionButton.visible) { + HUD_ICON_NO_BASE_2.drawTinted2(this.productionButton.x, this.productionButton.y, var5); + } + + if (this.projectsPanel != null && this.projectsPanel.flashing && this.projectsButton.visible) { + HUD_ICON_NO_BASE_3.drawTinted2(this.projectsButton.x, this.projectsButton.y, var5); + } + + if (this.fleetInfoPanel.flashing && this.fleetInfoButton.visible) { + HUD_ICON_NO_BASE_4.drawTinted2(this.fleetInfoButton.x, this.fleetInfoButton.y, var5); + } + + if (this.diplomacyPanel.flashing && this.diplomacyButton.visible) { + HUD_ICON_NO_BASE_1.drawTinted2(this.diplomacyButton.x, this.diplomacyButton.y, var5); + } + + if (this.victoryPanel != null && this.victoryPanel.flashing && this.victoryButton.visible) { + HUD_ICON_NO_BASE_5.drawTinted2(this.victoryButton.x, this.victoryButton.y, var5); + } + + for (final ListIterator> it = this.components.listIterator(this.components.size()); it.hasPrevious(); ) { + final UIComponent var12 = it.previous(); + if (var12 instanceof FloatingPanel) { + var12.draw(); + } + } + + final boolean var13; + boolean var14 = false; + String var8 = null; + boolean var9 = false; + final int var10 = Drawing.WHITE; + if (this.gameSession.gameState.hasEnded) { + var13 = this.gameSession.gameState.winnerIndex < 0; + if (this.gameSession.localPlayer != null && (this.gameSession.gameState.isPlayerDefeated(this.gameSession.localPlayer.index) || this.gameSession.gameState.victoryChecker.isLoser(this.gameSession.localPlayer))) { + var14 = true; + } + + var8 = !var14 ? (!var13 ? StringConstants.TEXT_VICTORY : StringConstants.TEXT_PEACE) : StringConstants.TEXT_DEFEAT; + if (this.gameSession.localPlayer == null && !var13) { + var8 = Strings.format(StringConstants.TEXT_PLAYER_HAS_WON, this.gameSession.gameState.players[this.gameSession.gameState.winnerIndex].name); + } + } + + if (this.gameSession.localPlayer != null && this.gameSession.gameState.isPlayerDefeated(this.gameSession.localPlayer.index) && this._I) { + var9 = true; + var8 = StringConstants.TEXT_DEFEAT; + } + + if (var8 != null) { + Menu.FONT.drawCentered(var8, 320, 240, var10, GameView.uiPulseCounter); + int var11 = Menu.SMALL_FONT.ascent + 245; + //noinspection StringEquality + if (var8 == StringConstants.TEXT_PEACE) { + final String s = this.gameSession.gameState.anyPlayersDefeated() ? StringConstants.TEXT_PEACE_3 : StringConstants.TEXT_PEACE_2; + Menu.SMALL_FONT.drawCentered(s, 320, var11, var10, GameView.uiPulseCounter); + var11 += 3 + Menu.SMALL_FONT.ascent; + } + + Menu.SMALL_FONT.drawCentered(StringConstants.TEXT_TOGGLE_STATS, 320, var11, var10, GameView.uiPulseCounter); + if (var9) { + var11 += Menu.SMALL_FONT.ascent + 3; + Menu.SMALL_FONT.drawCentered(StringConstants.TEXT_TOGGLE_STATS_2, 320, var11, var10, GameView.uiPulseCounter); + } + } + + if (this.newTurnPanelOpenAmount != 0) { + this.drawNewTurnPanel(); + } + + if (this.statsScreenOpenAmount != 0) { + this.drawStatsScreen(); + } + + if (this.hoveredComponent != null && this.hoveredComponent.tooltip != null) { + this.a209(this.hoveredComponent.tooltip); + } + + } + + private void a652(final int var1, final int var2, final int var4) { + final String var5 = StringConstants.TURN_OBJECTIVE.toUpperCase() + ": " + StringConstants.GAME_TYPE_TOOLTIPS[0]; + Menu.SMALL_FONT.drawParagraph(var5, 5 + var1, var4 + 5, var2 - 10, ShatteredPlansClient.SCREEN_HEIGHT, Drawing.WHITE, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, Menu.SMALL_FONT.ascent); + } + + public boolean isProductionWindowOpen() { + return this.productionPanel.visible; + } + + public void updateAvailableFleetCounters() { + final ProductionPanelState var2 = this.productionPanel.state; + for (int i = 0; i < var2.buildFleetsLabels.size(); ++i) { + final Label button = var2.buildFleetsLabels.get(i); + final Force force = button.data; + button.text = Integer.toString(force.fleetsAvailableToBuild); + button.tooltip = var2.buildFleetsButtons.get(i).tooltip = ProductionPanelState.buildingFleetsTooltip(force.fleetsAvailableToBuild); + } + } + + public void initialize(final ClientGameSession session) { + this.gameSession = session; + this.initialize(); + } + + public void setActionHint(final String message) { + final StatusPanelState var4 = (StatusPanelState) this.statusPanel.state; + + if (Menu.SMALL_FONT.measureLineWidth(message) < 400) { + var4.label.setTextAndLeftAlign(message); + var4.label.setPosition(15, -(3 * Menu.SMALL_FONT.ascent / 4) + (this.statusPanel.y + this.statusPanel.height / 2 - 1)); + } else { + final int var5 = message.indexOf(" ", message.length() / 2); + final String var6 = message.substring(0, var5) + "
" + message.substring(var5 + 1); + var4.label.setTextAndLeftAlign(var6); + var4.label.setPosition(15, -(Menu.SMALL_FONT.ascent * 5 / 4) + (this.statusPanel.y + this.statusPanel.height / 2 - 1)); + } + } + + private void a423() { + this.newTurnPanelOpenAmount = 0; + if (this.animationAutoPlayButton.isActive() && this.gameSession.turnEventLog != null) { + this.gameSession.gameView.advanceAnimationPhase(AbstractGameView.AnimationPhase.BUILD, this.gameSession.turnEventLog.events); + this.animationPlayingButton.activate(); + this.animationPlayingButton.tooltip = StringConstants.TOOLTIP_ANIM_CLICK_TO_STOP; + } else { + this.gameSession.gameView.advanceAnimationPhase(AbstractGameView.AnimationPhase.NOT_PLAYING, Collections.emptyList()); + this.gameSession.recalculateSystemState(); + this.animationPlayingButton.deactivate(); + this.animationPlayingButton.tooltip = StringConstants.TOOLTIP_ANIM_CLICK_TO_PLAY; + } + } + + public void h150() { + if (this.gameSession.isTutorial) { + if (JagexApplet.lastTypedKeyCode == KeyState.Code.ENTER) { + TutorialState.a984fl("enter"); + } + } + + if (JagexApplet.lastTypedKeyCode == KeyState.Code.ENTER) { + this.gameSession.gameView.stopCombatAnimations(); + this.gameSession.recalculateSystemState(); + } + + if (JagexApplet.lastTypedKeyCode == KeyState.Code.SPACE) { + if (this.gameSession.gameState.playerCount == 1) { + return; + } + + this.isStatsScreenOpen = !this.isStatsScreenOpen; + if (this.isStatsScreenOpen && this.gameSession.localPlayer != null && this.gameSession.gameState.isPlayerDefeated(this.gameSession.localPlayer.index)) { + this._I = false; + } + + final int var2 = this.gameSession.gameState.playerCount; + this._l = new String[16][var2]; + this._G = new int[16][]; + final int[][] var3 = new int[16][var2]; + final Player[] var4 = this.gameSession.gameState.players; + + int var5; + for (var5 = 0; var5 < var4.length; ++var5) { + final Player var6 = var4[var5]; + final int[] var7 = var6.stats.b341(); + final String[] var8 = var6.stats.a061(); + + for (int var9 = 0; var9 < 16; ++var9) { + var3[var9][var6.index] = var7[var9]; + this._l[var9][var6.index] = var8[var9]; + } + } + + this._q = new int[16][var2]; + + for (int var10 = 0; var10 < 16; ++var10) { + this._G[var10] = GameState.calculateRanksAscending(var3[var10]); + + for (var5 = 0; var2 > var5; ++var5) { + int var11 = 0; + + for (int var12 = 0; var12 < var2; ++var12) { + if (var3[var10][var12] <= var3[var10][var5]) { + ++var11; + } + } + + this._q[var10][var5] = var2 - var11; + } + } + } + + if (JagexApplet.lastTypedKeyCode == KeyState.Code.LETTER_C) { + _gen = !_gen; + this.showChat.toggle(); + } + } + + public int getHeight() { + if (this.gameSession.isTutorial) { + return JagexApplet.gameHeight; + } else { + return this.gameSession.isMultiplayer ? Component._tgc.y : this._O.y; + } + } + + private void m150() { + currentSettings = 0; + if (this.animationAutoPlayButton.isActive()) { + currentSettings |= 32; + } + + if (this.animationSpeedDoubledButton.isActive()) { + currentSettings |= 64; + } + + } + + private void drawNewTurnPanel() { + int var2 = 32; + if (this.newTurnPanelOpenAmount >= 32) { + if (this.newTurnPanelOpenAmount > 59968) { + var2 = '\uea60' - this.newTurnPanelOpenAmount; + } + } else { + var2 = this.newTurnPanelOpenAmount; + } + + final int var3 = MathUtil.ease(var2, 32, 21, 450); + fadeRect(0, 0, ShatteredPlansClient.SCREEN_WIDTH, ShatteredPlansClient.SCREEN_HEIGHT, (-var2 + 32 << 6) / 32 + 192); + final int var4 = (ShatteredPlansClient.SCREEN_WIDTH - var3) / 2; + final byte var5 = 80; + final short var6 = 250; + Menu.drawShine(var4, var5, var3, var6, 3974311, true); + final int[] var7 = new int[4]; + Drawing.saveBoundsTo(var7); + Drawing.setBounds(var4 + Menu.SMALL_FONT.ascent / 2, var5, -(Menu.SMALL_FONT.ascent / 2) + var4 + var3, 330); + final VictoryChecker var9 = this.gameSession.gameState.victoryChecker; + String var8; + if (var9 instanceof CaptureAndHoldVictoryChecker) { + var8 = StringConstants.TEXT_MAP_SOL; + } else if (var9 instanceof PointsVictoryChecker) { + var8 = StringConstants.TEXT_MAP_POINTS; + } else if (var9 instanceof DerelictsVictoryChecker) { + var8 = StringConstants.TEXT_MAP_DERELICTS; + } else { + var8 = StringConstants.TEXT_MAP_HEX; + } + + var8 = var8 + " "; + if (this.gameSession.gameState.gameOptions.simpleGarrisoning) { + var8 = var8 + StringConstants.TEXT_GARRISON_NO; + } else { + var8 = var8 + StringConstants.TEXT_GARRISON_YES; + } + + Menu.SMALL_FONT.draw(var8.toUpperCase(), 10 + var4, Menu.SMALL_FONT.ascent + var5, Drawing.WHITE); + Menu.drawShine(var4 + Menu.SMALL_FONT.ascent / 2, Menu.SMALL_FONT.ascent + var5 + 5, -Menu.SMALL_FONT.ascent + 450 + 1, 10 + FACTION_ICONS_LARGE[0].height, 0); + int var10 = 0; + if (this.gameSession.localPlayer != null) { + var10 = this.gameSession.localPlayer.index; + } + + final Sprite var11 = new Sprite(FACTION_ICONS_LARGE[0].height, -Menu.SMALL_FONT.ascent + 450 - (10 + FACTION_ICONS_LARGE[0].width / 2)); + Drawing.saveContext(); + var11.installForDrawing(); + Drawing.fillRectangleVerticalGradient(0, 0, var11.width, var11.height, this.gameSession.gameState.players[var10].color1, 0); + Drawing.restoreContext(); + var11.f797(); + var11.draw(5 + Menu.SMALL_FONT.ascent / 2 + var4, Menu.SMALL_FONT.ascent + var5 + 10, 64); + final ArgbSprite var12 = new ArgbSprite(FACTION_ICONS_LARGE[0].width, FACTION_ICONS_LARGE[0].height); + + for (int var13 = 0; FACTION_ICONS_LARGE[var10].pixels.length > var13; ++var13) { + if ((-16777216 & FACTION_ICONS_LARGE[var10].pixels[var13]) == 0) { + var12.pixels[var13] = 0; + } else { + var12.pixels[var13] = -16777216; + } + } + + var12.draw(5 + var4 + Menu.SMALL_FONT.ascent / 2 + (var11.width - FACTION_ICONS_LARGE[0].width / 2), 10 + var5 + Menu.SMALL_FONT.ascent); + FACTION_ICONS_LARGE[var10].draw(-(FACTION_ICONS_LARGE[0].width / 2) + var11.width + Menu.SMALL_FONT.ascent / 2 + var4 + 5, Menu.SMALL_FONT.ascent + var5 + 10, 64); + final String var16 = Strings.format(StringConstants.TURN_ORDINAL, Integer.toString(1 + this.gameSession.gameState.turnNumber)); + final int var14 = 10 + FACTION_ICONS_LARGE[0].height + var5 + 20 + Menu.FONT.ascent; + Menu.FONT.drawCentered(var16, 320, var14, Drawing.WHITE); + final int var15 = this.newTurnPanelOpenAmount - 32; + if (var15 > 0) { + if (var15 >= 32) { + Menu.SMALL_FONT.drawCentered(this.turnName, 320, var14 + Menu.SMALL_FONT.ascent + 3, 2458760); + } else { + Menu.SMALL_FONT.drawCentered(this.turnName, 320, 3 + var14 + Menu.SMALL_FONT.ascent, 2458760, var15 * 8); + } + } + + if (var9 instanceof ConquestVictoryChecker) { + this.a652(var4 + Menu.SMALL_FONT.ascent / 2 + 5, 439 - Menu.SMALL_FONT.ascent, var5 + Menu.SMALL_FONT.ascent); + } + + if (var9 instanceof CaptureAndHoldVictoryChecker) { + this.c115(Menu.SMALL_FONT.ascent / 2 + var4 + 5, Menu.SMALL_FONT.ascent + var5, 450 - Menu.SMALL_FONT.ascent - 11); + } + + if (var9 instanceof PointsVictoryChecker) { + this.b115(-Menu.SMALL_FONT.ascent + 450 - 11, Menu.SMALL_FONT.ascent + var5, Menu.SMALL_FONT.ascent / 2 + var4 + 5); + } + + if (var9 instanceof DerelictsVictoryChecker) { + this.a115(5 + Menu.SMALL_FONT.ascent / 2 + var4, -Menu.SMALL_FONT.ascent + 439, Menu.SMALL_FONT.ascent + var5); + } + + Drawing.restoreBoundsFrom(var7); + } + + private int[][] getAnimatedStatsGraphData() { + if (this.targetStatsGraphData == null) { + return null; + } + if (this.statsGraphData == null || this.statsGraphData[0] == null) { + this.statsGraphTurnAdvanceAnimationCounter = 0; + this.statsGraphData = this.targetStatsGraphData; + this.statsGraphStartTurn = this.statsGraphTurnCount; + } + + if (this.targetStatsGraphData[0].length != this.statsGraphData[0].length) { + return null; + } else if (this.statsGraphTurnAdvanceAnimationCounter == 0) { + return this.statsGraphData; + } else { + final int playerCount = this.gameSession.gameState.playerCount; + final int turnCount = this.targetStatsGraphData[0].length; + final int[][] data = new int[playerCount][]; + + for (int i = 0; i < playerCount; ++i) { + final int[] prev = this.statsGraphData[i]; + final int[] next = this.targetStatsGraphData[i]; + data[i] = IntStream.range(0, turnCount) + .map(j -> MathUtil.ease(this.statsGraphTurnAdvanceAnimationCounter, STATS_GRAPH_TURN_ADVANCE_ANIMATION_COUNTER_MAX, prev[j], next[j])) + .toArray(); + } + + return data; + } + } + + public void destroy() { + this.components.forEach(UIComponent::destroy); + this.projectsPanel = null; + this.animationAutoPlayButton = null; + this.productionPanel = null; + this.diplomacyPanel = null; + this.victoryButton = null; + this.fleetInfoPanel = null; + this.diplomacyButton = null; + this.animationSpeedDoubledButton = null; + this.projectsButton = null; + this.victoryPanel = null; + this.fleetInfoButton = null; + this.statusPanel = null; + this.endTurnButton = null; + this.animationPlayingButton = null; + this.productionButton = null; + } + + public void updateForTurnStart() { + this.f150(); + if (this.projectsPanel != null) { + this.updateProjectsPanel(); + } + for (final Player player : this.gameSession.gameState.players) { + this.updateDiplomacyState(player); + } + + this.diplomacyPanel.flashing = false; + this.diplomacyButton.deactivate(); + this.e150(); + if (this.fleetsTabButton.isActive()) { + this.selectStatsScreenTab(StatsScreenTab.FLEETS); + } else if (this.productionTabButton.isActive()) { + this.selectStatsScreenTab(StatsScreenTab.PRODUCTION); + } else if (this.systemsTabButton.isActive()) { + this.selectStatsScreenTab(StatsScreenTab.SYSTEMS); + } else if (this.overviewTabButton.isActive()) { + this.selectStatsScreenTab(StatsScreenTab.OVERVIEW); + } + + if (this.gameSession.isTutorial) { + TutorialState.k150pe(); + this.a423(); + } else if (ClientGameSession.isAutoPlaying) { + this.a423(); + } else { + this.turnName = this.gameSession.gameState.turnName(); + this.newTurnPanelOpenAmount = 1; + Sounds.play(Sounds.SFX_NEXT_OPEN); + } + } + + public boolean processInput(final boolean var1) { + if (this.statsScreenOpenAmount != 0) { + this.processInputStatsScreen(); + return true; + } else if (this.newTurnPanelOpenAmount == 0) { + return this.processInputHud(var1); + } else { + if (JagexApplet.mouseButtonJustClicked != MouseState.Button.NONE) { + if (this.newTurnPanelOpenAmount < 32) { + this.newTurnPanelOpenAmount = -this.newTurnPanelOpenAmount + 60000; + Sounds.play(Sounds.SFX_NEXT_CLOSE); + } else if (this.newTurnPanelOpenAmount < 59968) { + this.newTurnPanelOpenAmount = 59968; + Sounds.play(Sounds.SFX_NEXT_CLOSE); + } + } + return true; + } + } + + private boolean processInputHud(final boolean var1) { + final boolean var3 = this.hoveredComponent != null || Component._tgc.y <= JagexApplet.mouseY || this._O != null && this._O.y <= JagexApplet.mouseY; + this.processMouseInput(this.components); + if (this.mouseDownComponent != null) { + for (final UIComponent var4 : this.components) { + if (var4 instanceof FloatingPanel var5) { + if (var5.visible && var5.hasChild(this.mouseDownComponent)) { + this.a690(var5); + var5.flashing = false; + if (var5 == this.productionPanel) { + this.productionButton.deactivate(); + } + + if (var5 == this.projectsPanel) { + this.projectsButton.deactivate(); + } + + if (var5 == this.diplomacyPanel) { + this.diplomacyButton.deactivate(); + } + + if (var5 == this.fleetInfoPanel) { + this.fleetInfoButton.deactivate(); + } + + if (var5 == this.victoryPanel) { + this.victoryButton.deactivate(); + } + break; + } + } + } + } + + if (this.clickedComponent != null) { + if (this.clickedComponent.data instanceof FloatingPanel clickedTarget2) { + clickedTarget2.visible = false; + if (clickedTarget2 == this.productionPanel) { + this.productionButton.tooltip = StringConstants.TOOLTIP_PRODUCTION_BUTTON_SHOW; + this.productionButton.deactivate(); + } + + if (clickedTarget2 == this.projectsPanel) { + this.projectsButton.tooltip = StringConstants.TOOLTIP_PROJECTS_BUTTON_SHOW; + this.projectsButton.deactivate(); + } + + if (clickedTarget2 == this.diplomacyPanel) { + this.diplomacyButton.tooltip = StringConstants.TOOLTIP_DIPLOMACY_BUTTON_SHOW; + this.diplomacyButton.deactivate(); + } + + if (clickedTarget2 == this.fleetInfoPanel) { + this.fleetInfoButton.tooltip = StringConstants.TOOLTIP_FLEET_INFO_BUTTON_SHOW; + this.fleetInfoButton.deactivate(); + } + + if (clickedTarget2 == this.victoryPanel) { + this.victoryButton.tooltip = StringConstants.TOOLTIP_VICTORY_BUTTON_SHOW; + this.victoryButton.deactivate(); + } + + clickedTarget2.flashing = false; + return var3; + } + + if (this.clickedComponent == this.productionButton) { + if (this.productionPanel.visible) { + this.productionPanel.visible = false; + this.productionButton.tooltip = StringConstants.TOOLTIP_PRODUCTION_BUTTON_SHOW; + } else { + this.a690(this.productionPanel); + this.productionButton.tooltip = StringConstants.TOOLTIP_PRODUCTION_BUTTON_HIDE; + this.productionPanel.visible = true; + } + + this.productionPanel.flashing = false; + this.productionButton.deactivate(); + return var3; + } + + if (this.clickedComponent == this.projectsButton) { + if (this.projectsPanel.visible) { + this.projectsButton.tooltip = StringConstants.TOOLTIP_PROJECTS_BUTTON_SHOW; + this.projectsPanel.visible = false; + } else { + this.a690(this.projectsPanel); + this.projectsButton.tooltip = StringConstants.TOOLTIP_PROJECTS_BUTTON_HIDE; + this.projectsPanel.visible = true; + } + + this.projectsPanel.flashing = false; + this.projectsButton.deactivate(); + return var3; + } + + if (this.clickedComponent == this.diplomacyButton) { + if (this.diplomacyPanel.visible) { + this.diplomacyButton.tooltip = StringConstants.TOOLTIP_DIPLOMACY_BUTTON_SHOW; + this.diplomacyPanel.visible = false; + } else { + this.a690(this.diplomacyPanel); + this.diplomacyButton.tooltip = StringConstants.TOOLTIP_DIPLOMACY_BUTTON_HIDE; + this.diplomacyPanel.visible = true; + } + + this.diplomacyPanel.flashing = false; + this.diplomacyButton.deactivate(); + return var3; + } + + if (this.clickedComponent == this.fleetInfoButton) { + if (this.fleetInfoPanel.visible) { + this.fleetInfoPanel.visible = false; + this.fleetInfoButton.tooltip = StringConstants.TOOLTIP_FLEET_INFO_BUTTON_SHOW; + } else { + this.a690(this.fleetInfoPanel); + this.fleetInfoButton.tooltip = StringConstants.TOOLTIP_FLEET_INFO_BUTTON_HIDE; + this.fleetInfoPanel.visible = true; + } + + this.fleetInfoPanel.flashing = false; + this.fleetInfoButton.deactivate(); + return var3; + } + + if (this.clickedComponent == this.victoryButton) { + if (this.victoryPanel.visible) { + this.victoryPanel.visible = false; + } else { + this.a690(this.victoryPanel); + this.victoryPanel.visible = true; + } + this.victoryButton.tooltip = StringConstants.TOOLTIP_VICTORY_BUTTON_SHOW; + + this.victoryPanel.flashing = false; + this.victoryButton.deactivate(); + return var3; + } + + if (this.clickedComponent == this.endTurnButton) { + this.endTurnButtonClicked(); + return var3; + } + + if (this.clickedComponent == this.showChat) { + _gen = !_gen; + this.showChat.toggle(); + return var3; + } + + if (this.clickedComponent == this.animationAutoPlayButton) { + this.animationAutoPlayButton.toggle(); + if (this.animationAutoPlayButton.isActive()) { + this.animationAutoPlayButton.tooltip = StringConstants.TOOLTIP_ANIM_AUTO_PLAY_IS_ON; + if (this.gameSession.turnEventLog != null) { + this.gameSession.gameView.advanceAnimationPhase(AbstractGameView.AnimationPhase.BUILD, this.gameSession.turnEventLog.events); + if (!this.animationPlayingButton.isActive()) { + this.animationPlayingButton.toggle(); + this.animationPlayingButton.tooltip = StringConstants.TOOLTIP_ANIM_CLICK_TO_STOP; + } + } + } else { + this.animationAutoPlayButton.tooltip = StringConstants.TOOLTIP_ANIM_AUTO_PLAY_IS_OFF; + if (this.animationPlayingButton.isActive()) { + this.animationPlayingButton.toggle(); + this.animationPlayingButton.tooltip = StringConstants.TOOLTIP_ANIM_CLICK_TO_PLAY; + } + + this.gameSession.gameView.advanceAnimationPhase(AbstractGameView.AnimationPhase.NOT_PLAYING, this.gameSession.turnEventLog == null ? null : this.gameSession.turnEventLog.events); + this.gameSession.recalculateSystemState(); + } + + this.m150(); + return var3; + } + + if (this.clickedComponent == this.animationPlayingButton) { + if (this.gameSession.turnEventLog != null) { + this.animationPlayingButton.toggle(); + } + + if (this.animationPlayingButton.isActive()) { + this.animationPlayingButton.tooltip = StringConstants.TOOLTIP_ANIM_CLICK_TO_STOP; + this.gameSession.gameView.advanceAnimationPhase(AbstractGameView.AnimationPhase.BUILD, this.gameSession.turnEventLog == null ? null : this.gameSession.turnEventLog.events); + } else { + this.animationPlayingButton.tooltip = StringConstants.TOOLTIP_ANIM_CLICK_TO_PLAY; + this.gameSession.gameView.advanceAnimationPhase(AbstractGameView.AnimationPhase.NOT_PLAYING, this.gameSession.turnEventLog == null ? null : this.gameSession.turnEventLog.events); + this.gameSession.recalculateSystemState(); + } + + return var3; + } + + if (this.clickedComponent == this.animationSpeedDoubledButton) { + this.animationSpeedDoubledButton.toggle(); + if (this.animationSpeedDoubledButton.isActive()) { + this.animationSpeedDoubledButton.tooltip = StringConstants.TOOLTIP_ANIM_SPEED_IS_DOUBLE; + } else { + this.animationSpeedDoubledButton.tooltip = StringConstants.TOOLTIP_ANIM_SPEED_IS_NORMAL; + } + + this.m150(); + return var3; + } + + if (this.gameSession.localPlayer != null && this.productionPanel.visible) { + final ProductionPanelState panelState = this.productionPanel.state; + for (int i = 0; i < panelState._f.size(); ++i) { + final ScrollView var6 = panelState._f.get(i); + final Force force = var6.data; + if (var6.hasChild(this.clickedComponent)) { + if (this.gameSession.placementMode == PlacementMode.BUILD_FLEET && this.gameSession.selectedForce == force) { + this.setPlacementMode(PlacementMode.NONE); + } else if (force.fleetsAvailableToBuild > 0) { + this.activateFleetPlacement(force, false); + } + } + } + } + + if (this.gameSession.localPlayer != null && this.projectsPanel.visible) { + final ProjectsPanelState var11 = this.projectsPanel.state; + + for (final int type : GameState.RESOURCE_TYPES) { + if (var11._c[type].hasChild(this.clickedComponent) && this.gameSession.localPlayer.researchPoints[type] == GameState.MAX_RESEARCH_POINTS) { + this.activateProject(type); + } + } + } + + if (this.gameSession.localPlayer != null && this.diplomacyPanel.visible) { + final DiplomacyPanelState var12 = this.diplomacyPanel.state; + for (final ScrollView var17 : var12._h) { + final Player player = var17.data; + if (player != this.gameSession.localPlayer && var17.hasChild(this.clickedComponent) && !this.gameSession.localPlayer.allies[player.index]) { + this.gameSession.requestOrAcceptPact(player); + } + } + } + } + + if (!var3 && this.gameSession.isTutorial) { + if (TutorialState.a881ks(var1)) { + return true; + } + } + + return var3; + } + + private void a209(final String var2) { + int var3 = JagexApplet.mouseX + 10; + int var4 = JagexApplet.mouseY + 20; + final int var5 = Menu.SMALL_FONT.measureLineWidth(var2); + if (13 + var4 > ShatteredPlansClient.SCREEN_HEIGHT) { + var3 = JagexApplet.mouseX; + var4 = JagexApplet.mouseY - 15; + } + + if (10 + var5 + var3 > 639) { + var3 = -1 - var5 + 630; + } + + Drawing.fillRoundedRect(var3, var4, var5 + 10, 13, 5, 0, 192); + Drawing.f669(var3 - 1, var4 - 1, var5 + 12, 15, 6, 3974311); + Menu.SMALL_FONT.draw(var2, 6 + var3, 3 + var4 + Menu.SMALL_FONT.ascent / 2, Drawing.WHITE); + } + + private void initialize() { + if (!this.gameSession.isTutorial || TutorialState.stage >= 6) { + this.diplomacyPanel.content.removeChildren(); + final DiplomacyPanelState var2 = new DiplomacyPanelState(this.gameSession.gameState.playerCount); + this.diplomacyPanel.state = var2; + if (this.gameSession.localPlayer == null) { + for (int var3 = 0; var3 < this.gameSession.gameState.playerCount; ++var3) { + final ScrollView var4 = a583nl(var2, this.gameSession.gameState.players, this.gameSession.gameState.players[var3]); + var4.setPosition(this.diplomacyPanel.content.x, this.diplomacyPanel.content.y + this.diplomacyPanel.content.contentHeight); + this.diplomacyPanel.content.addChild(var4); + } + } else { + final ScrollView var6 = a583nl(var2, this.gameSession.gameState.players, this.gameSession.localPlayer); + var6.setPosition(this.diplomacyPanel.content.x, this.diplomacyPanel.content.y + this.diplomacyPanel.content.contentHeight); + this.diplomacyPanel.content.addChild(var6); + + for (int var7 = 0; this.gameSession.gameState.playerCount > var7; ++var7) { + if (this.gameSession.gameState.players[var7] != this.gameSession.localPlayer) { + final ScrollView var5 = a318lr(var2, this.gameSession.localPlayer, this.gameSession.gameState.players[var7], this.gameSession.gameState.players); + var5.setPosition(this.diplomacyPanel.content.x, this.diplomacyPanel.content.y + this.diplomacyPanel.content.contentHeight); + this.diplomacyPanel.content.addChild(var5); + } + } + } + } + } + + public void tick() { + if (this.gameSession.readyToEndTurn || this.endTurnButton == null) { + final StatusPanelState var2 = (StatusPanelState) this.statusPanel.state; + var2.icon.setSprite(null); + if (this.gameSession.playersWaitingOn == 1) { + this.setActionHint(StringConstants.TEXT_WAITING_FOR_PLAYER); + } else { + this.setActionHint(Strings.format(StringConstants.WAITING_FOR_N_PLAYERS, Integer.toString(this.gameSession.playersWaitingOn))); + } + } else { + this.endTurnButton.deactivate(); + } + + for (final Player players : this.gameSession.gameState.players) { + this.updateDiplomacyState(players); + } + + if (!this.gameSession.isMultiplayer && !this.gameSession.isTutorial) { + this.b150(); + } + + tickChat(); + this._V.setPosition(this._V.x, this.getHeight() - this._V.height / 2); + this._K.setPosition(this._K.x, this._V.y); + boolean var9 = false; + + for (int i = 0; i < this.gameSession.gameState.playerCount; ++i) { + final String message; + if (i == this.gameSession.localPlayerIndex) { + if (this.gameSession.gameState.isPlayerOfferingRematch(i)) { + if (this.gameSession.isUnrated) { + message = StringConstants.MP_YOU_OFFER_REMATCH_UNRATED; + } else { + message = StringConstants.MP_YOU_OFFER_REMATCH; + } + } else if (this.gameSession.gameState.didPlayerResign(i)) { + message = StringConstants.MP_YOU_RESIGNED; + } else if (this.gameSession.gameState.isPlayerDefeated(i)) { + message = StringConstants.TEXT_YOU_HAVE_BEEN_DEFEATED; + } else if (!this.gameSession.gameState.hasEnded && this.gameSession.gameState.isPlayerOfferingDraw(i)) { + message = StringConstants.MP_YOU_OFFER_DRAW; + } else { + message = null; + } + } else { + final String playerName = this.gameSession.gameState.playerNames[i]; + if (this.gameSession.didPlayerLeave(i)) { + if (this.gameSession.gameState.didPlayerResign(i)) { + message = Strings.format(StringConstants.MP_X_HAS_RESIGNED_AND_LEFT, playerName); + } else { + message = Strings.format(StringConstants.MP_X_HAS_LEFT, playerName); + } + } else if (this.gameSession.gameState.isPlayerOfferingRematch(i)) { + if (this.gameSession.isUnrated) { + message = Strings.format(StringConstants.MP_X_OFFERS_REMATCH_UNRATED, playerName); + } else { + message = Strings.format(StringConstants.MP_X_OFFERS_REMATCH, playerName); + } + } else if (this.gameSession.gameState.didPlayerResign(i)) { + message = Strings.format(StringConstants.MP_X_HAS_RESIGNED, playerName); + } else if (this.gameSession.gameState.isPlayerDefeated(i)) { + message = null; + } else if (!this.gameSession.gameState.hasEnded && this.gameSession.gameState.isPlayerOfferingDraw(i)) { + message = Strings.format(StringConstants.MP_X_WANTS_TO_DRAW, playerName); + } else { + message = null; + } + } + + if (message != null && !message.equals(this.playerDiplomacyStatusMessage[i])) { + this._z[i] = true; + } + + this.playerDiplomacyStatusMessage[i] = message; + var9 |= message != null; + } + + if (this.gameSession.localPlayer == null || this.gameSession.localPlayer.incomingPactOffersBitmap == 0) { + this.playerDiplomacyStatusMessage[this.gameSession.gameState.playerCount] = null; + } else { + var9 = true; + //noinspection StringEquality + if (this.playerDiplomacyStatusMessage[this.gameSession.gameState.playerCount] != StringConstants.MESSAGE_INCOMING_OFFERS) { + this.playerDiplomacyStatusMessage[this.gameSession.gameState.playerCount] = StringConstants.MESSAGE_INCOMING_OFFERS; + this._z[this.gameSession.gameState.playerCount] = true; + this.diplomacyPanel.flashing = true; + this.diplomacyButton.activate(); + } + } + + int var10; + if (var9) { + int var5 = 250; + if (this._ib) { + var5 = 5 * var5 >> 2; + } + + if (var5 <= ++this._x) { + do { + if (++this._U == this.playerDiplomacyStatusMessage.length) { + this._U = 0; + } + } while (this.playerDiplomacyStatusMessage[this._U] == null); + + this._x = 0; + final String _o = this.playerDiplomacyStatusMessage[this._U]; + this._ib = this._z[this._U]; + this._z[this._U] = false; + var10 = Menu.SMALL_FONT.measureLineWidth(_o); + this._T = new Sprite(var10, Menu.SMALL_FONT.descent + Menu.SMALL_FONT.ascent); + Drawing.saveContext(); + this._T.installForDrawing(); + Drawing.clear(); + Menu.SMALL_FONT.drawRightAligned(_o, this._T.width, Menu.SMALL_FONT.ascent, Drawing.WHITE); + this._eb = this._T.copy(); + this._eb.installForDrawing(); + Drawing.clear(); + Menu.SMALL_FONT.drawRightAligned(_o, this._T.width, Menu.SMALL_FONT.ascent, Drawing.WHITE); + Drawing.b669(1, 1, this._eb.width, this._eb.height); + Drawing.restoreContext(); + } + } else { + this._x = 250; + this._U = -1; + } + + if (this.newTurnPanelOpenAmount != 0) { + if (++this.newTurnPanelOpenAmount == 60000) { + this.a423(); + } + + if (this.newTurnPanelOpenAmount == 59968) { + Sounds.play(Sounds.SFX_NEXT_CLOSE); + } + } + + if (this.isStatsScreenOpen) { + if (this.statsScreenOpenAmount < 32) { + ++this.statsScreenOpenAmount; + } + } else if (this.statsScreenOpenAmount > 0) { + --this.statsScreenOpenAmount; + } + + if (this.statsScreenOpenAmount != 0) { + this.tickStatsScreen(); + } + + if (this.gameSession.isTutorial) { + TutorialState.tick(); + Drawing.saveContext(); + _fjr.installForDrawing(); + Drawing.fillRect(0, 0, _fjr.width, _fjr.height, 0); + if (TutorialState._sek) { + PRODUCTION_BUTTON.draw(10, 10); + final int var5 = Drawing.alphaOver(Drawing.WHITE, Drawing.BLACK, GameView.uiPulseCounter); + _fjr.f150(var5); + _fjr.f150(var5); + _fjr.installForDrawing(); + Drawing.b669(5, 5, _fjr.width, _fjr.height); + } + + _kbw.installForDrawing(); + Drawing.fillRect(0, 0, _kbw.width, _kbw.height, 0); + if (TutorialState._phg) { + READY_BUTTON.draw(10, 10); + final int var5 = Drawing.alphaOver(Drawing.WHITE, Drawing.BLACK, GameView.uiPulseCounter); + _kbw.f150(var5); + _kbw.f150(var5); + _kbw.installForDrawing(); + Drawing.b669(2, 2, _kbw.width, _kbw.height); + + for (var10 = 0; var10 < _kbw.pixels.length; ++var10) { + _kbw.pixels[var10] = Drawing.WHITE + (_kbw.pixels[var10] << 8 & 0xff000000); + } + } + + Drawing.restoreContext(); + } + } + + private void tickStatsScreen() { + if (this.statsGraphTurnAdvanceAnimationCounter != 0 && ++this.statsGraphTurnAdvanceAnimationCounter >= STATS_GRAPH_TURN_ADVANCE_ANIMATION_COUNTER_MAX) { + this.statsGraphData = this.targetStatsGraphData; + this.statsGraphStartTurn = this.statsGraphTurnCount; + this.statsGraphTurnAdvanceAnimationCounter = 0; + } + + if (this.currentStatsScreenTab != StatsScreenTab.OVERVIEW && this.targetStatsGraphData != null) { + if ((this.statsGraphAlpha += 8) > 256) { + this.statsGraphAlpha = 256; + } + } else if ((this.statsGraphAlpha -= 8) < 0) { + this.statsGraphAlpha = 0; + } + + if (++this._p[this._w] > 32) { + this._p[this._w] = 32; + } + + final int playerCount = this.gameSession.gameState.playerCount; + int var4 = 210; + int var5; + int var6; + if (playerCount == 2) { + for (var5 = 0; var5 < 4; ++var5) { + var6 = var4 / (4 - var5); + this._ob[var5] = 12 + var6; + var4 -= var6; + } + } else { + var5 = var4 / (6 + playerCount); + var6 = 12 + 2 * var5; + int var7 = -(8 * var5) + var4; + this._ob[this._w] = var6 + var7; + final int var8 = MathUtil.ease(this._p[this._w], 32, 0, var7); + var7 -= var8; + final int[] var9 = new int[4]; + int var10 = 0; + + for (int var11 = 0; var11 < 4; ++var11) { + if (this._w != var11) { + final int var12 = MathUtil.ease(this._p[var11], 32, 0, 1024); + var9[var11] = var12; + var10 += var12; + } + } + + if (var10 == 0) { + for (int var11 = 0; var11 < 4; ++var11) { + if (var11 != this._w) { + this._ob[var11] = var6 + var7 / 3; + this._ob[this._w] -= var7 / 3; + } + } + } else { + for (int var11 = 0; var11 < 4; ++var11) { + if (var11 != this._w) { + this._ob[var11] = var7 * var9[var11] / var10 + var6; + this._ob[this._w] -= var7 * var9[var11] / var10; + } + } + } + } + + var5 = MathUtil.ease(this.statsScreenOpenAmount, 32, 20, 550); + this.fleetsTabControl.setPosition(20 + (ShatteredPlansClient.SCREEN_WIDTH - var5) / 2, this.fleetsTabButton.y); + this.productionTabControl.setPosition(5 + this.fleetsTabButton.width + (ShatteredPlansClient.SCREEN_WIDTH - var5) / 2 + 20, this.productionTabButton.y); + this.systemsTabControl.setPosition(2 * (this.fleetsTabButton.width + 5) + (ShatteredPlansClient.SCREEN_WIDTH - var5) / 2 + 20, this.systemsTabButton.y); + this.overviewTabControl.setPosition((ShatteredPlansClient.SCREEN_WIDTH - var5) / 2 + 20 + (this.fleetsTabButton.width + 5) * 3, this.overviewTabButton.y); + } + + private void b150() { + final int var2 = 400; + final int var3 = var2 - ShatteredPlansClient._flh * ShatteredPlansClient._flh; + final int var4 = 360 + 120 * var3 / var2; + this._O.setBounds(0, var4, ShatteredPlansClient.SCREEN_WIDTH, 120); + this._E.content.children.clear(); + int var5 = 0; + int var6 = 0; + + int var7; + for (var7 = ShatteredPlansClient.chatMessageCount - 1; var7 >= 0; --var7) { + final funorb.client.lobby.ChatMessage var8 = ShatteredPlansClient.chatMessages[var7]; + final boolean var9 = ShatteredPlansClient._kpi > var5; + if (var9) { + if (var8.component == null) { + final int var10 = var8._g; + var8.component = new Component<>(Component.UNSELECTED_LABEL, var8.message); + var8.component.mouseOverTextColor = ((16711422 & Component.UNSELECTED_LABEL.mouseOverTextColor) >> 1) + var10 - (var10 >> 1 & 8355711); + var6 += 15; + var8.component.font = Component.CHAT_FONT; + var8.component.textColor = var10; + var8.component._qb = (8355711 & Component.UNSELECTED_LABEL._qb >> 1) - ((var10 & 16711422) >> 1) + var10; + } + + ++var5; + } else { + var8.component = null; + } + } + + var7 = 0; + + int var11; + for (var11 = 0; var11 < ShatteredPlansClient.chatMessageCount; ++var11) { + final funorb.client.lobby.ChatMessage var12 = ShatteredPlansClient.chatMessages[var11]; + if (var12.component != null) { + this._E.content.addChild(var12.component); + var12.component.setBounds(ShatteredPlansClient._tga, var7, var12.component.e474(), 15); + var7 += 15; + } + } + + var11 = -var7 + var6 + this._E.content._gb + this._E.content.height; + this._E.content.y += var11; + this._E.content.height = var7; + this._E.content._gb = 0; + final int var13 = this._E.viewport.height - this._E.content.height - this._E.content._gb; + if (this._v) { + this._E.content._w = var13 - this._E.content.y; + } + + this._E.a795(30 * JagexApplet.mouseWheelRotation, 15); + this._v = var13 == this._E.content.y + this._E.content._w; + this._O.rootProcessMouseEvents(true); + } + + private void a690(final FloatingPanel var2) { + assert this.components.indexOf(this._V) == 0 && this.components.indexOf(this._K) == 1; + this.components.remove(var2); + this.addComponent(var2, 2); + } + + private String a436(int var2) { + final int var3 = var2 / 60; + var2 %= 60; + + return String.valueOf((char) (48 + var3 / 10)) + + (char) (48 + var3 % 10) + + ':' + + (char) (var2 / 10 + 48) + + (char) (var2 % 10 + 48); + } + + public Rect b520() { + if (this.gameSession.isTutorial) { + return TutorialState.b520b(); + } else { + return new Rect(0, 50, ShatteredPlansClient.SCREEN_WIDTH, 430); + } + } + + private void f150() { + this.productionPanel.content.removeChildren(); + final ProductionPanelState info = this.productionPanel.state; + if (this.gameSession.localPlayer != null && !this.gameSession.gameState.isPlayerDefeated(this.gameSession.localPlayer.index)) { + if (this.gameSession.gameState.gameOptions.unifiedTerritories) { + info.buildFleetsButtons = new ArrayList<>(1); + info._f = new ArrayList<>(1); + info.buildFleetsLabels = new ArrayList<>(1); + final ScrollView var3 = addForceToProductionPanel(this.gameSession.localPlayer.combinedForce, info, true); + var3.setPosition(this.productionPanel.content.x, this.productionPanel.content.contentHeight + this.productionPanel.content.y); + this.productionPanel.content.addChild(var3); + if (this.gameSession.localPlayer.combinedForce.fleetsAvailableToBuild <= 0) { + this.productionPanel.flashing = false; + this.productionButton.deactivate(); + } else { + this.productionPanel.flashing = true; + this.productionButton.activate(); + } + } else { + final int forcesCount = this.gameSession.localPlayer.contiguousForces.size(); + info.buildFleetsButtons = new ArrayList<>(forcesCount); + info._f = new ArrayList<>(forcesCount); + info.buildFleetsLabels = new ArrayList<>(forcesCount); + this.productionPanel.flashing = false; + this.productionButton.deactivate(); + + boolean isFirst = true; + for (final ContiguousForce force : this.gameSession.localPlayer.contiguousForces) { + final ScrollView var5 = addForceToProductionPanel(force, info, isFirst); + var5.setPosition(this.productionPanel.content.x, this.productionPanel.content.y + this.productionPanel.content.contentHeight); + this.productionPanel.content.addChild(var5); + if (force.fleetsAvailableToBuild > 0) { + this.productionPanel.flashing = true; + this.productionButton.activate(); + } + isFirst = false; + } + } + } + + if (this.gameSession.localPlayer != null && (!this.gameSession.isTutorial || TutorialState.stage >= 5)) { + this.productionPanel.content.addChild(a179hc(this.productionPanel.content.x, this.productionPanel.content.contentHeight + this.productionPanel.content.y)); + } + + final Player[] var10 = this.gameSession.gameState.players; + + for (final Player var13 : var10) { + if (var13 != this.gameSession.localPlayer && !this.gameSession.gameState.isPlayerDefeated(var13.index)) { + if (this.gameSession.gameState.gameOptions.unifiedTerritories) { + final ScrollView var14 = a278an(var13.combinedForce, true); + var14.setPosition(this.productionPanel.content.x, this.productionPanel.content.contentHeight + this.productionPanel.content.y); + this.productionPanel.content.addChild(var14); + } else { + boolean isFirst = true; + for (final ContiguousForce force : var13.contiguousForces) { + final ScrollView var7 = a278an(force, isFirst); + var7.setPosition(this.productionPanel.content.x, this.productionPanel.content.contentHeight + this.productionPanel.content.y); + this.productionPanel.content.addChild(var7); + isFirst = false; + } + } + } + } + + int var12 = 3 + this.productionPanel.content.contentHeight + 20; + if (var12 > 363) { + var12 = 363; + } + + this.productionPanel.a183(var12, this.productionPanel.width); + this.productionPanel.content.a183(var12 - 10 - 18, this.productionPanel.content.width); + info.scrollBar.a183(var12 - 3 - 15 - 10, info.scrollBar.width); + info.scrollBar.enabled = var12 == 363; + + } + + private void endTurnButtonClicked() { + this.gameSession.gameView.stopCombatAnimations(); + this.gameSession.recalculateSystemState(); + if (this.gameSession.localPlayer != null) { + final StatusPanelState var2 = (StatusPanelState) this.statusPanel.state; + if (var2.icon.isEmpty() && this.gameSession.placementMode != PlacementMode.BUILD_FLEET) { + if (this.gameSession.gameState.gameOptions.unifiedTerritories) { + if (this.gameSession.localPlayer.combinedForce.fleetsAvailableToBuild > 0) { + this.activateFleetPlacement(this.gameSession.localPlayer.combinedForce, true); + return; + } + } else { + for (final ContiguousForce var3 : this.gameSession.localPlayer.contiguousForces) { + if (var3.fleetsAvailableToBuild > 0) { + this.activateFleetPlacement(var3, true); + return; + } + } + } + } + + this.gameSession.endTurn(); + this.endTurnButton.activate(); + var2.icon.setSprite(null); + if (this.gameSession.playersWaitingOn == 1) { + this.setActionHint(StringConstants.TEXT_WAITING_FOR_PLAYER); + } else { + this.setActionHint(Strings.format(StringConstants.WAITING_FOR_N_PLAYERS, Integer.toString(this.gameSession.playersWaitingOn))); + } + } + } + + private void a115(final int var1, final int var2, final int var4) { + final String var5 = StringConstants.TURN_OBJECTIVE.toUpperCase() + ": " + StringConstants.GAME_TYPE_TOOLTIPS[3]; + Menu.SMALL_FONT.drawParagraph(var5, 5 + var1, var4 + 5, var2 - 10, ShatteredPlansClient.SCREEN_HEIGHT, Drawing.WHITE, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, Menu.SMALL_FONT.ascent); + int var6 = 20 + var4 + Menu.SMALL_FONT.ascent + 9; + final int var7 = 64 + Menu.SMALL_FONT.measureLineWidth("= " + Strings.format(StringConstants.TURN_FEWER_SHIPS, Integer.toString(2))); + StarSystem.ALIEN_MINER.b115((-var7 + var2) / 2 + var1, var6 - 24, 64, 64); + Menu.SMALL_FONT.draw(Strings.format(StringConstants.TURN_POINTS, Integer.toString(2)), var1 - (-((var2 - var7) / 2) - 75), var6 + 7, Drawing.WHITE); + Menu.SMALL_FONT.draw("=", var1 + (var2 - var7) / 2 + 64, 13 + var6, Drawing.WHITE); + Menu.SMALL_FONT.draw(Strings.format(StringConstants.TURN_FEWER_SHIPS, Integer.toString(2)), 75 + (var2 - var7) / 2 + var1, 19 + var6, Drawing.WHITE); + var6 += 44; + StarSystem.ALIEN_SHIP.b115((-var7 + var2) / 2 + var1, var6 - 24, 64, 64); + Menu.SMALL_FONT.draw(Strings.format(StringConstants.TURN_POINTS, Integer.toString(2)), 75 + (-var7 + var2) / 2 + var1, 7 + var6, Drawing.WHITE); + Menu.SMALL_FONT.draw("=", (-var7 + var2) / 2 + var1 + 64, 13 + var6, Drawing.WHITE); + Menu.SMALL_FONT.draw(Strings.format(StringConstants.TURN_FEWER_SHIPS, Integer.toString(2)), 75 + (var2 - var7) / 2 + var1, var6 + 19, Drawing.WHITE); + var6 += 52; + StarSystem.ALIEN_BASE.b115(var1 + (var2 - var7) / 2, var6 - 24, 64, 64); + Menu.SMALL_FONT.draw(Strings.format(StringConstants.TURN_POINTS, Integer.toString(5)), 75 + (-var7 + var2) / 2 + var1, var6 + 7, Drawing.WHITE); + Menu.SMALL_FONT.draw("=", 64 + var1 + (-var7 + var2) / 2, 13 + var6, Drawing.WHITE); + Menu.SMALL_FONT.draw(Strings.format(StringConstants.TURN_FEWER_SHIPS, Integer.toString(5)), var1 - (-((-var7 + var2) / 2) - 75), 19 + var6, Drawing.WHITE); + } + + public void updateVictoryPanel(final int var1, final Player[] players, final int[] var3, final int[] var4, final Player[] leaders, final Label[] labels, final int turnsUntilVictory) { + final ScrollView content = this.victoryPanel.content; + content.removeChildren(); + final ScrollView labelView = createScrollView(labels); + labelView.setPosition(content.x, content.y + content.contentHeight); + content.addChild(labelView); + + for (int i = 0; i < players.length; ++i) { + final ScrollView var12 = createVictoryPanelRow(this.gameSession.gameState, leaders, var1, turnsUntilVictory, players[i], var4[i], var3[i]); + var12.setPosition(content.x, content.y + content.contentHeight); + content.addChild(var12); + } + + if (turnsUntilVictory > 0 && turnsUntilVictory <= 3) { + this.victoryPanel.flashing = true; + this.victoryButton.activate(); + } else { + this.victoryPanel.flashing = false; + this.victoryButton.deactivate(); + } + } + + public void activateFleetPlacement(final Force force, final boolean showUnplacedWarning) { + this.gameSession.selectedForce = force; + this.setPlacementMode(PlacementMode.BUILD_FLEET); + this.productionPanel.state.activateFleetPlacement(force); + + if (showUnplacedWarning) { + final StatusPanelState statusState = (StatusPanelState) this.statusPanel.state; + statusState.icon.setSprite(this.warningSprite); + statusState.label.setPosition(55, statusState.label.y); + if (this.gameSession.isTutorial) { + TutorialState.a984fl("unplaced"); + } + } + + for (final StarSystem system : force) { + this.gameSession.gameView.highlightedSystems[system.index] = SystemHighlight.TARGET; + } + } + + public enum PlacementMode { + MOVE_FLEET_SRC, + MOVE_FLEET_DEST, + BUILD_FLEET, + DEFENSIVE_NET, + TERRAFORM, + STELLAR_BOMB, + GATE_SRC, + GATE_DEST; + + /** + * When no other placement mode is active, the placement mode is implicitly + * {@link PlacementMode#MOVE_FLEET_SRC}. + */ + public static final PlacementMode NONE = MOVE_FLEET_SRC; + } + + private enum StatsScreenTab { + FLEETS, // = 0; + PRODUCTION, // = 1; + SYSTEMS, // = 2; + OVERVIEW, // = 3; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/JagexApplet.java b/src/main/java/funorb/shatteredplans/client/JagexApplet.java new file mode 100644 index 0000000..8a02825 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/JagexApplet.java @@ -0,0 +1,2545 @@ +package funorb.shatteredplans.client; + +import funorb.Strings; +import funorb.awt.KeyState; +import funorb.awt.MouseState; +import funorb.awt.MouseWheelState; +import funorb.cache.BufferedCacheFile; +import funorb.cache.CacheWorker; +import funorb.cache.MasterIndexLoader; +import funorb.cache.PageSource; +import funorb.cache.RemotePageSource; +import funorb.cache.ResourceLoader; +import funorb.client.AchievementRequest; +import funorb.client.EmailLoginCredentials; +import funorb.client.GetProfileRequest; +import funorb.client.JagexBaseApplet; +import funorb.client.LoginCredentials; +import funorb.client.LoginState; +import funorb.client.ReflectionRequest; +import funorb.client.SetProfileRequest; +import funorb.client.UserIdLoginCredentials; +import funorb.client.e_; +import funorb.client.DisplayMode; +import funorb.client.intro.JagexLogoIntroAnimation; +import funorb.client.lobby.ChatMessage; +import funorb.client.lobby.ContextMenu; +import funorb.client.lobby.PlayerListEntry; +import funorb.client.lobby.QuickChatResponse; +import funorb.client.lobby.QuickChatResponses; +import funorb.client.lobby.ScrollPane; +import funorb.client.r_; +import funorb.commonui.CommonUI; +import funorb.commonui.CreateAccountPage; +import funorb.commonui.Enum1; +import funorb.commonui.form.CreateAccountForm; +import funorb.commonui.form.CreateDisplayNameForm; +import funorb.commonui.form.DobToEnableChatForm; +import funorb.commonui.form.validator.ConfirmEmailValidator; +import funorb.commonui.form.validator.UsernameValidator; +import funorb.commonui.kj_; +import funorb.io.Buffer; +import funorb.io.CipheredBuffer; +import funorb.io.DuplexStream; +import funorb.io.HuffmanCoder; +import funorb.io.PacketLengthType; +import funorb.shatteredplans.C2SPacket; +import funorb.shatteredplans.S2CPacket; +import funorb.shatteredplans.StringConstants; +import funorb.util.IsaacCipher; +import funorb.util.PseudoMonotonicClock; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.applet.Applet; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Image; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.OptionalDataException; +import java.io.PrintWriter; +import java.io.StreamCorruptedException; +import java.io.StringReader; +import java.io.StringWriter; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.Socket; +import java.net.URL; +import java.security.SecureRandom; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Optional; +import java.util.Queue; +import java.util.Random; +import java.util.stream.LongStream; + +public abstract class JagexApplet extends JagexBaseApplet { + private static final Queue achievementRequests = new ArrayDeque<>(); + protected static final Queue profileSetRequests = new ArrayDeque<>(); + private static final int UPDATE = 15; + private static final Color LOADING_SCREEN_PURPLE = new Color(0x9933ff); + public static boolean DEBUG_MODE = false; + public static final int SERVER_TIMEOUT_MILLIS = 30_000; + public static final Random cipherIVGen = new Random(); + public static final Buffer loginPacket = new Buffer(256); + protected static final Queue getProfileResponses = new ArrayDeque<>(); + public static final SecureRandom secureRandom = new SecureRandom(); + public static kj_ _tplc; + public static boolean isAnonymous = true; + public static String _aeg; + protected static boolean _vmNb; + @MagicConstant(valuesFromClass = KeyState.Code.class) + public static int lastTypedKeyCode; + public static char lastTypedKeyChar; + private static int _ffu; + private static Image _rma; + private static int _igd; + private static int _npj; + protected static int[] _uof; + protected static RemotePageSource pageSource; + private static int[] _gsc; + private static long _coo; + public static String lastLoginPassword; + public static int membershipLevel; + private static Applet _eic; + public static boolean canOnlyQuickChat; + private static int[] _clrzb; + private static r_ _vag; + public static int adminLevel; + private static MasterIndexLoader masterIndexLoader; + public static int mouseY = 0; + @MagicConstant(valuesFromClass = MouseState.Button.class) + public static int mouseButtonJustClicked = 0; + public static boolean mouseEventReceived = false; + protected static int nextS2cPacketLen; + public static QuickChatResponses _dhc; + private static int[] _red; + private static boolean[] _aqp; + private static MailboxMessage socketMessage2; + private static long _amCb; + private static DuplexStream serverConnection2; + private static long lastC2sMessageTimestamp; + private static Boolean _sad; + private static long serverCipherIV; + private static int[] _fy; + private static int _efa; + private static final int IDLE_TICKS = 60_000; + public static final boolean[] keysDown = new boolean[112]; + private static final int[] cipherIV = new int[4]; + private static final char[] _pdkf = new char[]{'_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + private static final String[] CONNECTING_TO_UPDATE_SERVER = new String[]{"Connecting to update server", "Verbinde mit Aktualisierungsserver", "Connexion au serveur de mise à jour", "Conectando ao servidor de atualização", "Met updateserver verbinden", "Connecting to update server (untranslated)"}; + private static final String[] LOADING_TEXT = new String[]{"Loading text", "Lade Text", "Chargement du texte", "Carregando textos", "Tekst laden", "Cargando texto"}; + private static final String[] WAITING_FOR_TEXT = new String[]{"Waiting for text", "Warte auf Text", "En attente du texte", "Aguardando textos", "Op tekst wachten", "Esperando a texto"}; + private static final String[] _nla = new String[255]; + public static int gameHeight; + public static int gameWidth; + protected static String connectingToUpdateServerMessage; + protected static String loadingTextMessage; + protected static String waitingForTextMessage; + public static String playerDisplayName; + protected static final CipheredBuffer s2cPacket = new CipheredBuffer(); + private static String normalizedPlayerName; + protected static @NotNull ChatMessage.Channel _D = ChatMessage.Channel.LOBBY; + @MagicConstant(valuesFromClass = MouseState.Button.class) + public static int mouseButtonDown = 0; + public static int mousePressX = 0; + public static int mousePressY = 0; + public static int modLevel; + private static int _feJ; + private static int _se; + public static int _jmt; + public static boolean _npm; + private static int _wmc; + private static int _usb; + private static LoginCredentials loginCredentials = null; + private static BufferedCacheFile _vca; + private static boolean _kej; + private static long lastRecievedDataFromServer; + private static int[] _lgd; + public static int langId; + private static String sessionId; + private static String _cju; + private static String[] _aee; + private static int _gpc; + public static int mouseX = 0; + public static String _umj; + protected static LoginState loginState; + @MagicConstant(valuesFromClass = ConnectionState.class) + public static int connectionState; + private static int[] _ajd; + public static int mouseWheelRotation; + private static java.awt.Font _haa; + private int gamePort1Primary; + private int gamePort1Secondary; + private static MailboxMessage socketMessage1; + protected static DuplexStream serverConnection1; + private int gamePort2Primary; + private int gamePort2Secondary; + private static String _nlc; + public static boolean cannotChat = true; + protected static long _bqe; + private static boolean _mdB; + protected static long _ipb; + private static @NotNull JagexApplet.LoadingStatus _qjg = LoadingStatus.OK_COMPLETE; + @MagicConstant(valuesFromClass = LoadStage.class) + protected static int loadStage; + private static long userId; + private static int reinitializationCount = 0; + private static boolean isSimpleModeEnabled; + private static int _naL; + private static int _gbi; + private boolean isMember; + private int gamePort1; + private int gamePort2; + private String codeHost; + private long instanceId; + private int affId; + private boolean isJagexHost; + private int serverId; + + public static void printDebug(final String message) { + if (DEBUG_MODE) { + System.out.println(message); + } + } + + protected JagexApplet() { + } + + private static void initializeLoadingMessages(final int langId) { + connectingToUpdateServerMessage = CONNECTING_TO_UPDATE_SERVER[langId]; + waitingForTextMessage = WAITING_FOR_TEXT[langId]; + loadingTextMessage = LOADING_TEXT[langId]; + } + + private static void a681nc(final ChatMessage message) { + if (message._l != 0 || message._e != 0) { + if (Arrays.stream(ShatteredPlansClient.chatMessages, 0, ShatteredPlansClient.chatMessageCount) + .anyMatch(existing -> existing.channel == ChatMessage.Channel.PRIVATE + && message._l == existing._l + && message._e == existing._e)) { + return; + } + } + + if (message._f != null) { + ShatteredPlansClient._cvco = message.senderName; + _bqe = message.senderId; + _uof = message._f; + _D = message.channel; + } + + ContextMenu.showChatMessage(message); + } + + private static void setPlayerDisplayName(final String newName) { + playerDisplayName = newName; + normalizedPlayerName = Strings.normalize(playerDisplayName); + } + + protected static Frame createFullScreenFrame() { + int bitDepth = 0; + final DisplayMode[] modes = listDisplayModes(); + + boolean foundMode = false; + for (final DisplayMode mode : modes) { + if (mode.width == ShatteredPlansClient.SCREEN_WIDTH + && mode.height == ShatteredPlansClient.SCREEN_HEIGHT + && (!foundMode || bitDepth < mode.bitDepth)) { + foundMode = true; + bitDepth = mode.bitDepth; + } + } + + if (!foundMode) { + return null; + } + + final MailboxMessage message = MessagePumpThread.instance.sendEnterFullScreenMessage(bitDepth); + message.busyAwait(); + + final Frame frame = (Frame) message.response; + if (frame == null) { + return null; + } else if (message.status == MailboxMessage.Status.FAILURE) { + repeatedlyTryToExitFullScreen(frame); + return null; + } else { + return frame; + } + } + + private static void processMouseState() { + synchronized (MouseState.instance) { + ++MouseState.ticksSinceLastMouseEvent; + + mouseEventReceived = MouseState.mouseEventReceived; + MouseState.mouseEventReceived = false; + + mouseButtonDown = MouseState.mouseButtonDown; + mouseX = MouseState.mouseX; + mouseY = MouseState.mouseY; + + mouseButtonJustClicked = MouseState.mouseButtonJustClicked; + mousePressX = MouseState.pressX; + mousePressY = MouseState.pressY; + MouseState.mouseButtonJustClicked = MouseState.Button.NONE; + } + } + + private static String getUsernameOrEmail() { + if (CommonUI._eel == Enum1.C3) { + return _umj; + } else if (CommonUI._fjs == Enum1.C3) { + return UsernameValidator._gpb; + } else { + return ConfirmEmailValidator._wha.b154() ? CommonUI.enteredUsername : UsernameValidator._gpb; + } + } + + private static void processKeyState() { + synchronized (KeyState.instance) { + ++KeyState.ticksSinceLastKeyEvent; + KeyState.keyTypeQueueFront = _feJ; + if (KeyState.keyPressQueueBack < 0) { + // we couldn't keep up! reset all the state + Arrays.fill(keysDown, false); + KeyState.keyPressQueueBack = KeyState.keyPressQueueFront; + } else { + while (KeyState.keyPressQueueFront != KeyState.keyPressQueueBack) { + final int var1 = KeyState.keyPressQueue[KeyState.keyPressQueueFront]; + KeyState.keyPressQueueFront = (KeyState.keyPressQueueFront + 1) & 127; + if (var1 >= 0) { + keysDown[var1] = true; + } else { + keysDown[~var1] = false; + } + } + } + + _feJ = KeyState.keyTypeQueueBack; + } + } + + public static void clientError(final Throwable var1, final String var2) { + try { + String var3 = ""; + if (var1 != null) { + var3 = a900es(var1); + } + + if (var2 != null) { + if (var1 != null) { + var3 = var3 + " | "; + } + + var3 = var3 + var2; + } + + System.out.println("Error: " + ChatMessage.a651("%0a", var3, "\n")); + var3 = ChatMessage.a651(":", var3, "%3a"); + var3 = ChatMessage.a651("@", var3, "%40"); + var3 = ChatMessage.a651("&", var3, "%26"); + var3 = ChatMessage.a651("#", var3, "%23"); + if (_eic == null) { + return; + } + + final MailboxMessage var4 = MessagePumpThread.instance.sendOpenUrlStreamMessage(new URL(_eic.getCodeBase(), "clienterror.ws?c=" + getInstance().gameCrc + "&u=" + "" + _coo + "&v1=" + MessagePumpThread.JAVA_VENDOR + "&v2=" + MessagePumpThread.JAVA_VERSION + "&e=" + var3)); + + while (var4.status == MailboxMessage.Status.PENDING) { + JagexBaseApplet.maybeSleep(1L); + } + + if (var4.status == MailboxMessage.Status.SUCCESS) { + final DataInputStream var5 = (DataInputStream) var4.response; + //noinspection ResultOfMethodCallIgnored + var5.read(); + var5.close(); + } + } catch (final Exception var6) { + } + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + protected static boolean isConnectedAndLoaded() { + return connectionState >= ConnectionState.CONNECTED && loadStage >= LoadStage.LOADED; + } + + @SuppressWarnings("SameParameterValue") + private static void handleProfilePacket(final CipheredBuffer packet) { + final int var2 = packet.readUByte(); + if (var2 == 0) { + Optional.ofNullable(getProfileResponses.poll()).ifPresentOrElse(var3 -> { + final int var4 = packet.readUByte(); + final byte[] var5; + if (var4 == 0) { + var5 = null; + } else { + var5 = new byte[var4]; + packet.readBytes(var5, var4); + } + + packet.pos += 4; + if (!packet.f427()) { + shutdownServerConnection(); + return; + } + + var3.completed = true; + var3.data = var5; + }, JagexApplet::shutdownServerConnection); + } else if (var2 == 1) { + final int digest = packet.readInt(); + profileSetRequests.stream().filter(request -> request.digest == digest).findFirst() + .ifPresentOrElse(profileSetRequests::remove, JagexApplet::shutdownServerConnection); + } else { + clientError(null, "A1: " + a738w()); + shutdownServerConnection(); + } + } + + @Contract(pure = true) + protected static String a019pd(long var0) { + if (var0 > 0L && var0 < 6582952005840035281L) { + if (var0 % 37L == 0L) { + return null; + } else { + final int var2 = (int) LongStream.iterate(var0, var3 -> var3 != 0L, var3 -> var3 / 37L).count(); + + final StringBuilder var5; + char var9; + for (var5 = new StringBuilder(var2); var0 != 0L; var5.append(var9)) { + final long var7 = var0; + var0 /= 37L; + var9 = _pdkf[(int) (var7 - var0 * 37L)]; + if (var9 == '_') { + final int var10 = var5.length() - 1; + var5.setCharAt(var10, Character.toUpperCase(var5.charAt(var10))); + var9 = 160; + } + } + + var5.reverse(); + var5.setCharAt(0, Character.toUpperCase(var5.charAt(0))); + return var5.toString(); + } + } else { + return null; + } + } + + public static void repeatedlyTryToExitFullScreen(final Frame frame) { + while (true) { + final MailboxMessage message = MessagePumpThread.instance.sendExitFullScreenMessage(frame); + if (message.busyAwait() == MailboxMessage.Status.SUCCESS) { + frame.setVisible(false); + frame.dispose(); + return; + } + maybeSleep(100L); + } + } + + private static String a124ck(final Applet var0) { + return _cju != null ? _cju : var0.getParameter("settings"); + } + + private static LoginCredentials createLoginCredentials(final String username, final String password) { + long userId = 0L; + String email = null; + if (username.indexOf('@') == -1) { + userId = UserIdLoginCredentials.encodeUsername(username); + } else { + email = username; + } + + return createLoginCredentials(email, userId, password); + } + + private static void a423r() { + final CipheredBuffer packet = s2cPacket; + final int var1 = packet.readUByte(); + Menu.rankingsRequests.stream() + .filter(var3 -> var3._k == var1) + .findFirst().ifPresentOrElse(var2 -> { + final int var4 = packet.readUByte(); + if (var4 != 0) { + final int var5 = var2._j; + _nla[0] = playerDisplayName; + + int var6; + for (var6 = 1; var4 > var6; ++var6) { + _nla[var6] = packet.readNullTerminatedString(); + } + + a599uic(var5, var4); + + for (var6 = 0; var4 > var6; ++var6) { + a277tvc(packet); + if (var6 == 0) { + var2._i = _npj; + var2._l = _naL; + var2._h = _igd; + var2._r = _gpc; + a669pm(_naL, _npj, _gpc, 0, _igd); + } else { + a669pm(_naL, _npj, _gpc, var6, _igd); + } + } + + a366bh(var5); + final String[][] var12 = var2._n = new String[2][var5]; + final int[][] var7 = var2._m = new int[2][4 * var5]; + final int var8 = _wmc; + int var9 = 0; + + int var10; + int var11; + for (var10 = 0; var8 > var9; ++var9) { + var11 = _lgd[var9]; + var12[0][var10] = _nla[var11]; + var7[0][4 * var10] = _f[var11]; + var7[0][var10 * 4 + 1] = _clrzb[var11]; + var7[0][2 + var10 * 4] = _ajd[var11]; + var7[0][var10 * 4 + 3] = _fy[var11]; + if (a623jp(_nla[var11]) && _fy[var11] + _ajd[var11] + _clrzb[var11] == 0) { + var12[0][var10] = null; + --var10; + } + + ++var10; + } + + int i = 0; + + for (var10 = 0; var8 > i; ++var10) { + var11 = _lgd[i + var5]; + var12[1][var10] = _nla[var11]; + var7[1][4 * var10] = _f[var11]; + var7[1][4 * var10 + 1] = _clrzb[var11]; + var7[1][var10 * 4 + 2] = _ajd[var11]; + var7[1][var10 * 4 + 3] = _fy[var11]; + if (a623jp(_nla[var11]) && _clrzb[var11] + _ajd[var11] + _fy[var11] == 0) { + var12[1][var10] = null; + --var10; + } + + ++i; + } + } + + var2._q = true; + Menu.rankingsRequests.remove(var2); + }, JagexApplet::shutdownServerConnection); + } + + private static void a277tvc(final Buffer var0) { + _npj = var0.readUShort() << 5; + final int var1 = var0.readUByte(); + _npj += var1 >> 3; + _gpc = 1835008 & var1 << 18; + _gpc += var0.readUShort() << 2; + final int i = var0.readUByte(); + _gpc += i >> 6; + _igd = 2064384 & i << 15; + _igd += var0.readUByte() << 7; + final int j137 = var0.readUByte(); + _naL = (1 & j137) << 16; + _igd += j137 >> 1; + _naL += var0.readUShort(); + } + + private static void a366bh(final int var0) { + a394ai(var0, true, 0, _wmc, _efa, _usb); + + int var1 = 0; + while (_wmc > var1) { + _lgd[var1 + var0] = var1++; + } + + a394ai(var0 + var0, false, var0, _wmc + var0, _ffu, _se); + if (_wmc > var0) { + _wmc = var0; + } + + } + + private static void a599uic(final int var0, final int var1) { + if (_red == null || var1 > _red.length) { + _red = new int[var1 * 2]; + } + + if (_f == null || var1 > _f.length) { + _f = new int[var1 * 2]; + } + + if (_clrzb == null || var1 > _clrzb.length) { + _clrzb = new int[var1 * 2]; + } + + if (_ajd == null || var1 > _ajd.length) { + _ajd = new int[2 * var1]; + } + + if (_fy == null || var1 > _fy.length) { + _fy = new int[2 * var1]; + } + + if (_gsc == null || _gsc.length < var1) { + _gsc = new int[var1 * 2]; + } + + if (_lgd == null || var1 + var0 > _lgd.length) { + _lgd = new int[2 * (var0 + var1)]; + } + + if (_aqp == null || _aqp.length < var1) { + _aqp = new boolean[2 * var1]; + } + + _wmc = 0; + _ffu = Integer.MAX_VALUE; + _se = Integer.MIN_VALUE; + _usb = Integer.MIN_VALUE; + _efa = Integer.MAX_VALUE; + } + + private static void handlePendingReflectionRequests() { + while (anyPendingReflectionRequests()) { + C2SPacket.buffer.writeCipheredByte(8); + final int lenPos = ++C2SPacket.buffer.pos; + respondToReflectionRequest(); + C2SPacket.buffer.insertLengthByte(C2SPacket.buffer.pos - lenPos); + } + } + + protected static void attachToCanvas(final Canvas canvas) { + KeyState.instance.attach(canvas); + MouseState.instance.attach(canvas); + MouseWheelState.instance.attach(canvas); + } + + protected static void detachFromCanvas(final Canvas canvas) { + KeyState.instance.detach(canvas); + MouseState.instance.detach(canvas); + MouseWheelState.instance.detach(canvas); + } + + public static void flushC2sPacket(final int n) { + if (serverConnection1 != null && (n < 0 || loginState == LoginState.LOGGED_IN)) { + if (C2SPacket.buffer.pos == 0 && lastC2sMessageTimestamp + 10000L < PseudoMonotonicClock.currentTimeMillis()) { + C2SPacket.buffer.writeCipheredByte(n); + } + + if (C2SPacket.buffer.pos > 0) { + try { + serverConnection1.write(C2SPacket.buffer.data, C2SPacket.buffer.pos); + lastC2sMessageTimestamp = PseudoMonotonicClock.currentTimeMillis(); + } catch (final IOException var3) { + shutdownServerConnection(); + } + + C2SPacket.buffer.pos = 0; + } + } else { + C2SPacket.buffer.pos = 0; + } + } + + public static boolean connectedAndLoggedIn() { + return serverConnection1 != null && loginState == LoginState.LOGGED_IN; + } + + public static void shutdownServerConnection() { + if (serverConnection1 != null) { + serverConnection1.close(); + serverConnection1 = null; + } + } + + protected static boolean f154jc() { + return connectionState >= ConnectionState.CONNECTED && !isAnonymous && !connectedAndLoggedIn(); + } + + @SuppressWarnings("SameParameterValue") + private static void handleAchievementsPacket(final CipheredBuffer packet) { + final int var1 = packet.readUByte(); + if (var1 == 0) { + final int[] var2 = new int[8]; + final int len = packet.readUByte(); + for (int i = 0; i < len; ++i) { + var2[i] = packet.readInt(); + } + + Optional.ofNullable(achievementRequests.poll()).ifPresentOrElse((req) -> { + req.areAchievementsOffline = false; + req.unlockedAchievementsBitmap = var2[0]; + req.completed = true; + }, JagexApplet::shutdownServerConnection); + } else if (var1 == 1) { + shutdownServerConnection(); + } else if (var1 == 2) { + Optional.ofNullable(achievementRequests.poll()).ifPresentOrElse(req -> { + req.unlockedAchievementsBitmap = 0; + req.completed = true; + req.areAchievementsOffline = true; + }, JagexApplet::shutdownServerConnection); + } else { + clientError(null, "A1: " + a738w()); + shutdownServerConnection(); + } + } + + public static void navigateToQuit(final Applet var1) { + navigateTo("quit.ws", var1); + } + + private static boolean anyPendingReflectionRequests() { + return Optional.ofNullable(ReflectionRequest.pending.peek()).map(req -> { + for (int i = 0; i < req.messageCount; ++i) { + if (req.fieldMessages[i] != null && req.fieldMessages[i].status == MailboxMessage.Status.PENDING) { + return false; + } + if (req.methodMessages[i] != null && req.methodMessages[i].status == MailboxMessage.Status.PENDING) { + return false; + } + } + return true; + }).orElse(false); + } + + private static void a813bs(final boolean var0) { + ConfirmEmailValidator._wha.a540(var0); + } + + private static void a077wo(final int var0, final String[] var2, final String var3) { + CommonUI._fjs = Enum1.C2; + if (var0 == 255) { + UsernameValidator._ija = ScrollPane.a705(_jmt < 13); + a786jp(null); + } else if (var0 >= 100 && var0 <= 105) { + a786jp(var2); + UsernameValidator._ija = a612tc(var2); + } else { + UsernameValidator._ija = CreateAccountPage.a431ck(var3, var0); + } + } + + private static void a453va(final String[] var0, final int var1, final String var2) { + CommonUI._eel = Enum1.C2; + if (var1 == 255) { + _tplc = ScrollPane.a705(_jmt < 13); + } else if (var1 >= 100 && var1 <= 105) { + _tplc = a612tc(var0); + } else { + _tplc = CreateAccountPage.a431ck(var2, var1); + } + } + + private static e_ j083bp() { + return new e_(a983of(), !ConfirmEmailValidator._wha.b154()); + } + + private static String a983of() { + if (CommonUI._eel == Enum1.C3) { + return _aeg; + } else if (ConfirmEmailValidator._wha.b154()) { + return CommonUI._fjs == Enum1.C3 ? ConfirmEmailValidator._wha.a738() : CommonUI.enteredUsername; + } else { + return ConfirmEmailValidator._wha.a738(); + } + } + + private static void navigateToReload(final Applet applet) { + try { + final String basePath = applet.getDocumentBase().getFile(); + final int queryIndex = basePath.indexOf('?'); + String reloadPage = "reload.ws"; + if (queryIndex >= 0) { + reloadPage = reloadPage + basePath.substring(queryIndex); + } + + final URL reloadUrl = new URL(applet.getCodeBase(), reloadPage); + applet.getAppletContext().showDocument(a236jg(applet, reloadUrl), "_self"); + } catch (final Exception var6) { + var6.printStackTrace(); + } + } + + private static URL a236jg(final Applet applet, final URL url) { + String var2 = null; + if (_cju != null && !_cju.equals(applet.getParameter("settings"))) { + var2 = _cju; + } + String var3 = null; + if (sessionId != null && !sessionId.equals(applet.getParameter("session"))) { + var3 = sessionId; + } + return a408np(url, var2, var3); + } + + private static URL a408np(final URL var3, final String var0, final String var2) { + String var4 = var3.getFile(); + int var5 = 0; + + while (true) { + int var6; + while (true) { + while (true) { + while (var4.regionMatches(var5, "/l=", 0, 3)) { + var6 = var4.indexOf('/', var5 + 1); + if (var6 < 0) { + break; + } + + var5 = var6; + } + + if (!var4.regionMatches(var5, "/a=", 0, 3)) { + break; + } + + var6 = var4.indexOf('/', var5 + 1); + if (var6 < 0) { + break; + } + + var5 = var6; + } + + if (!var4.regionMatches(var5, "/p=", 0, 3)) { + break; + } + + var6 = var4.indexOf('/', var5 + 1); + if (var6 < 0) { + break; + } + + if (var0 == null) { + var5 = var6; + } else { + var4 = var4.substring(0, var5) + var4.substring(var6); + } + } + + if (!var4.regionMatches(var5, "/s=", 0, 3) && !var4.regionMatches(var5, "/c=", 0, 3)) { + break; + } + + var6 = var4.indexOf('/', 1 + var5); + if (var6 < 0) { + break; + } + + if (var2 == null) { + var5 = var6; + } else { + var4 = var4.substring(0, var5) + var4.substring(var6); + } + } + + final StringBuilder var9 = new StringBuilder(var5); + var9.append(var4, 0, var5); + + if (var0 != null && var0.length() > 0) { + var9.append("/p="); + var9.append(var0); + } + + if (var2 != null && var2.length() > 0) { + var9.append("/s="); + var9.append(var2); + } + + if (var4.length() <= var5) { + var9.append('/'); + } else { + var9.append(var4.substring(var5)); + } + + try { + return new URL(var3, var9.toString()); + } catch (final Exception var8) { + var8.printStackTrace(); + return var3; + } + } + + @SuppressWarnings("SameParameterValue") + private static ChatMessage receiveChatMessage(final boolean isQuick, final CipheredBuffer packet) { + final int b0 = packet.readUByte(); + final boolean _tueb = (b0 & 128) != 0; + final ChatMessage.Channel channel = ChatMessage.Channel.decode(b0 & 127); + final int c = packet.readUByte(); + final long j = packet.readLong(); + final int l; + final int e; + if (channel == ChatMessage.Channel.PRIVATE) { + l = packet.readUShort(); + e = packet.readU24(); + } else { + l = 0; + e = 0; + } + + final boolean var4 = packet.readUByte() == 1; + final String senderDisplayName = packet.readNullTerminatedString(); + final String senderName; + if (var4) { + senderName = packet.readNullTerminatedString(); + } else { + senderName = senderDisplayName; + } + + final int _fmf; + final String _mcq; + if (channel == ChatMessage.Channel.ROOM || channel == ChatMessage.Channel.CHANNEL_5) { + _fmf = packet.readUShort(); + _mcq = packet.readNullTerminatedString(); + } else { + _fmf = 0; + _mcq = null; + } + + String message; + final int[] _mbp; + if (isQuick) { + final int var5 = packet.readUShort(); + final QuickChatResponse var6 = _dhc.get(var5); + message = var6.joinStrings(); + _mbp = senderName.equals(playerDisplayName) ? null : var6.ids; + } else { + try { + message = HuffmanCoder.instance.readEncoded(packet, 80); + } catch (final Exception ex) { + message = "Cabbage"; + } + _mbp = null; + } + + return new ChatMessage(isQuick, c, j, l, channel, e, senderDisplayName, _mbp, senderName, message, _tueb, _mcq, _fmf); + } + + private static void a394ai(final int var0, final boolean var1, final int var2, final int var3, final int var5, final int var6) { + if (var0 > var2) { + if (var3 > var2 + 1) { + int var7; + int var8; + int var9; + int var10; + if (5 + var2 < var3 && var5 != var6) { + var7 = (var6 >> 1) + (var5 >> 1) + (1 & var5 & var6); + var8 = var2; + var9 = var6; + var10 = var5; + + for (int var11 = var2; var3 > var11; ++var11) { + final int var12 = _lgd[var11]; + final int var13 = var1 ? _f[var12] : _gsc[var12]; + if (var7 < var13) { + _lgd[var11] = _lgd[var8]; + if (var13 < var9) { + var9 = var13; + } + + _lgd[var8++] = var12; + } else if (var10 < var13) { + var10 = var13; + } + } + + a394ai(var0, var1, var2, var8, var9, var6); + a394ai(var0, var1, var8, var3, var5, var10); + } else { + for (var7 = var3 - 1; var2 < var7; --var7) { + for (var8 = var2; var7 > var8; ++var8) { + var9 = _lgd[var8]; + var10 = _lgd[var8 + 1]; + if (a917aq(var10, var9, var1)) { + _lgd[var8] = var10; + _lgd[var8 + 1] = var9; + } + } + } + } + } + } + } + + private static String a755ql(final CharSequence var0) { + int var2 = var0.length(); + if (var2 > 20) { + var2 = 20; + } + + final char[] var3 = new char[var2]; + + for (int var4 = 0; var4 < var2; ++var4) { + final char var5 = var0.charAt(var4); + if (var5 >= 'A' && var5 <= 'Z') { + var3[var4] = (char) (var5 - 65 + 97); + } else if ((var5 < 'a' || var5 > 'z') && (var5 < '0' || var5 > '9')) { + var3[var4] = '_'; + } else { + var3[var4] = var5; + } + } + + return new String(var3); + } + + protected static boolean s2cBytesAvailable(final int len) { + if (s2cPacket.pos >= len) { + return true; + } + + if (serverConnection1 == null) { + return false; + } + if (hasConnectionTimedOut()) { + shutdownServerConnection(); + return false; + } + + try { + final int available = serverConnection1.inputAvailable(); + if (available > 0) { + final int bytesToRead = Math.min(available, len - s2cPacket.pos); + serverConnection1.read(s2cPacket.data, s2cPacket.pos, bytesToRead); + lastRecievedDataFromServer = PseudoMonotonicClock.currentTimeMillis(); + s2cPacket.pos += bytesToRead; + if (s2cPacket.pos < len) { + return false; + } + + s2cPacket.pos = 0; + return true; + } + } catch (final IOException var4) { + shutdownServerConnection(); + } + + return false; + } + + private static boolean hasConnectionTimedOut() { + // don't timeout the connection in debug mode + return !DEBUG_MODE && PseudoMonotonicClock.currentTimeMillis() - lastRecievedDataFromServer > SERVER_TIMEOUT_MILLIS; + } + + public static boolean a623jp(final String var0) { + return normalizedPlayerName.equals(Strings.normalize(var0)); + } + + private static void a786jp(final String[] var0) { + if (CreateAccountForm._anb != null) { + CreateAccountForm._anb._D.a449(var0); + } + + if (CommonUI._sjb != null) { + CommonUI._sjb._F.a449(var0); + } + } + + public static void a808bp(final String var0, final Applet var1) { + try { + URL var2 = new URL(var1.getCodeBase(), var0); + var2 = a236jg(var1, var2); + showDocument(var1, var2.toString()); + } catch (final Exception var3) { + var3.printStackTrace(); + } + } + + public static String a738w() { + String var1 = "(" + ShatteredPlansClient.thirdPreviousS2cPacketType + " " + ShatteredPlansClient.secondPreviousS2cPacketType + " " + ShatteredPlansClient.previousS2cPacketType + ") " + ShatteredPlansClient.currentS2cPacketType; + if (nextS2cPacketLen > 0) { + var1 = var1 + ":"; + + for (int var2 = 0; nextS2cPacketLen > var2; ++var2) { + var1 = var1 + ' '; + int var3 = 255 & s2cPacket.data[var2]; + int var4 = var3 >> 4; + var3 &= 15; + if (var4 >= 10) { + var4 += 55; + } else { + var4 += 48; + } + + if (var3 < 10) { + var3 += 48; + } else { + var3 += 55; + } + + var1 = var1 + (char) var4; + var1 = var1 + (char) var3; + } + } + + return var1; + } + + private static void respondToReflectionRequest() { + final ReflectionRequest req = ReflectionRequest.pending.poll(); + if (req != null) { + boolean anyStillPending = false; + + for (int i = 0; i < req.messageCount; ++i) { + if (req.fieldMessages[i] != null) { + if (req.fieldMessages[i].status == MailboxMessage.Status.FAILURE) { + req.statusCodes[i] = -5; + } + + if (req.fieldMessages[i].status == MailboxMessage.Status.PENDING) { + anyStillPending = true; + } + } + + if (req.methodMessages[i] != null) { + if (req.methodMessages[i].status == MailboxMessage.Status.FAILURE) { + req.statusCodes[i] = -6; + } + + if (req.methodMessages[i].status == MailboxMessage.Status.PENDING) { + anyStillPending = true; + } + } + } + + if (!anyStillPending) { + final int startPos = C2SPacket.buffer.pos; + C2SPacket.buffer.writeInt(req.id); + + for (int i = 0; i < req.messageCount; ++i) { + if (req.statusCodes[i] == ReflectionRequest.Status.OK) { + try { + final int type = req.types[i]; + if (type == ReflectionRequest.Type.STATIC_FIELD_GET) { + final Field field = (Field) req.fieldMessages[i].response; + C2SPacket.buffer.writeByte(0); + C2SPacket.buffer.writeInt(field.getInt(null)); + } else if (type == ReflectionRequest.Type.STATIC_FIELD_SET) { + final Field field = (Field) req.fieldMessages[i].response; + field.setInt(null, req.fieldValues[i]); + C2SPacket.buffer.writeByte(0); + } else if (type == ReflectionRequest.Type.FIELD_GET_MODIFIERS) { + final Field field = (Field) req.fieldMessages[i].response; + C2SPacket.buffer.writeByte(0); + C2SPacket.buffer.writeInt(field.getModifiers()); + } + + if (type == ReflectionRequest.Type.METHOD_INVOKE) { + final Method method = (Method) req.methodMessages[i].response; + + final byte[][] serializedParams = req.serializedParams[i]; + final Object[] params = new Object[serializedParams.length]; + for (int j = 0; j < serializedParams.length; ++j) { + params[j] = new ObjectInputStream(new ByteArrayInputStream(serializedParams[j])).readObject(); + } + + final Object result = method.invoke(null, params); + if (result == null) { + C2SPacket.buffer.writeByte(0); + } else if (result instanceof Number) { + C2SPacket.buffer.writeByte(1); + C2SPacket.buffer.writeLong(((Number) result).longValue()); + } else if (result instanceof String) { + C2SPacket.buffer.writeByte(2); + C2SPacket.buffer.writeNullTerminatedString((String) result); + } else { + C2SPacket.buffer.writeByte(4); + } + } else if (type == ReflectionRequest.Type.METHOD_GET_MODIFIERS) { + final Method method = (Method) req.methodMessages[i].response; + C2SPacket.buffer.writeByte(0); + C2SPacket.buffer.writeInt(method.getModifiers()); + } + } catch (final ClassNotFoundException var12) { + C2SPacket.buffer.writeByte(-10); + } catch (final InvalidClassException var13) { + C2SPacket.buffer.writeByte(-11); + } catch (final StreamCorruptedException var14) { + C2SPacket.buffer.writeByte(-12); + } catch (final OptionalDataException var15) { + C2SPacket.buffer.writeByte(-13); + } catch (final IllegalAccessException var16) { + C2SPacket.buffer.writeByte(-14); + } catch (final IllegalArgumentException var17) { + C2SPacket.buffer.writeByte(-15); + } catch (final InvocationTargetException var18) { + C2SPacket.buffer.writeByte(-16); + } catch (final SecurityException var19) { + C2SPacket.buffer.writeByte(-17); + } catch (final IOException var20) { + C2SPacket.buffer.writeByte(-18); + } catch (final NullPointerException var21) { + C2SPacket.buffer.writeByte(-19); + } catch (final Exception var22) { + C2SPacket.buffer.writeByte(-20); + } catch (final Throwable var23) { + C2SPacket.buffer.writeByte(-21); + } + } else { + C2SPacket.buffer.writeByte(req.statusCodes[i]); + } + } + + C2SPacket.buffer.writeDigest(startPos); + } + } + } + + private static void writeHandshake(final Buffer packet, final int serverId, final int langId) { + packet.writeByte(12); + packet.writeShort(17); + packet.writeShort(25); + packet.writeShort(serverId); + packet.writeByte(langId); + } + + private static void handleDisableChatRestrictionsPacket() { + cannotChat = false; + canOnlyQuickChat = s2cPacket.readUByte() == 0; + } + + private static void handleLevelPacket() { + final CipheredBuffer var1 = s2cPacket; + final int var2 = var1.readUByte(); + var1.readUByte(); + if (var2 == 0) { + shutdownServerConnection(); + } else if (var2 == 1) { + var1.d410(); + shutdownServerConnection(); + } else { + clientError(null, "LR1: " + a738w()); + shutdownServerConnection(); + } + } + + protected static boolean isS2cPacketFullyRecieved() { + if (nextS2cPacketLen == PacketLengthType.VARIABLE_BYTE_I) { + if (!s2cBytesAvailable(1)) { + return false; + } + + nextS2cPacketLen = s2cPacket.readUByte(); + s2cPacket.pos = 0; + } + + if (nextS2cPacketLen == PacketLengthType.VARIABLE_SHORT_I) { + if (!s2cBytesAvailable(2)) { + return false; + } + + nextS2cPacketLen = s2cPacket.readUShort(); + s2cPacket.pos = 0; + } + + return s2cBytesAvailable(nextS2cPacketLen); + } + + private static void writeRandomDat(@SuppressWarnings("SameParameterValue") final Buffer buffer) { + final byte[] var2 = new byte[24]; + if (_vca != null) { + try { + _vca.seek(0L); + _vca.read(var2); + + int var3 = 0; + while (var3 < 24 && var2[var3] == 0) { + ++var3; + } + + if (var3 >= 24) { + throw new IOException(); + } + } catch (final Exception var5) { + for (int var4 = 0; var4 < 24; ++var4) { + var2[var4] = -1; + } + } + } + + buffer.writeBytes(var2, 24); + } + + private static void showDocument(final Applet var0, final String var2) { + try { + var0.getAppletContext().showDocument(new URL(var2), "_blank"); + } catch (final MalformedURLException var4) { + clientError(null, "MGR1: " + var2); + } + } + + private static void a150ea() { + pageSource.failureCount = 0; + pageSource.errorCode = null; + } + + private static boolean a917aq(final int var0, final int var1, final boolean var2) { + if (var2) { + if (_f[var0] > _f[var1]) { + return true; + } + + if (_f[var1] > _f[var0]) { + return false; + } + + if (_gsc[var1] < _gsc[var0]) { + return true; + } + + if (_gsc[var1] > _gsc[var0]) { + return false; + } + } else { + if (_gsc[var0] > _gsc[var1]) { + return true; + } + + if (_gsc[var0] < _gsc[var1]) { + return false; + } + + if (_f[var0] > _f[var1]) { + return true; + } + + if (_f[var1] > _f[var0]) { + return false; + } + } + + final int var3 = _ajd[var1] + _clrzb[var1] + _fy[var1]; + final int var4 = _fy[var0] + _clrzb[var0] + _ajd[var0]; + if (var3 >= var4) { + if (var4 >= var3) { + return var0 > var1; + } else { + return false; + } + } else { + return true; + } + } + + private static void a150ij() { + if (_vca != null) { + try { + _vca.seek(0L); + _vca.write(s2cPacket.data, s2cPacket.pos, 24); + } catch (final Exception var2) { + } + } + + s2cPacket.pos += 24; + } + + @SuppressWarnings("SameParameterValue") + private static void handleHiscorePacket(final CipheredBuffer packet) { + final int var1 = packet.readUByte(); + if (var1 == 0) { + packet.readUShort(); + } else if (var1 == 1) { + packet.readUShort(); + packet.readLong(); + } else { + clientError(null, "HS1: " + a738w()); + } + shutdownServerConnection(); + } + + private static kj_ a612tc(final String[] var0) { + final kj_ var1 = new kj_(false); + var1._d = var0; + return var1; + } + + private static DisplayMode[] listDisplayModes() { + final MailboxMessage message = MessagePumpThread.instance.sendListDisplayModesMessage(); + if (message.busyAwait() == MailboxMessage.Status.FAILURE) { + return new DisplayMode[0]; + } + + final int[] values = (int[]) message.response; + final DisplayMode[] modes = new DisplayMode[values.length >> 2]; + + for (int i = 0; i < modes.length; ++i) { + final DisplayMode mode = new DisplayMode(); + modes[i] = mode; + mode.width = values[i << 2]; + mode.height = values[(i << 2) + 1]; + mode.bitDepth = values[(i << 2) + 2]; + } + + return modes; + } + + private static LoginCredentials createLoginCredentials(final String email, final long userId, final String password) { + if (userId == 0L && email != null) { + return new EmailLoginCredentials(email, password); + } else { + return new UserIdLoginCredentials(userId, password); + } + } + + private static boolean isCommonUiLoaded(final ResourceLoader spriteLoader, final ResourceLoader fontLoader, final ResourceLoader dataLoader) { + return spriteLoader.isIndexLoaded() && spriteLoader.loadGroupData("commonui") + && fontLoader.isIndexLoaded() && fontLoader.loadGroupData("commonui") + && dataLoader.isIndexLoaded() && dataLoader.loadGroupData("button.gif"); + } + + private static void initializeGameResourceLoaders() { + if (ResourceLoader.SHATTERED_PLANS_STRINGS_1 != null) { + StringConstants.loadShatteredPlans(ResourceLoader.SHATTERED_PLANS_STRINGS_1); + ResourceLoader.SHATTERED_PLANS_STRINGS_1 = null; + ShatteredPlansClient.resetFrameClock(); + } + + ResourceLoader.HUFFMAN_CODES = createResourceLoader(ResourceLoader.PageId.HUFFMAN_CODES); + ResourceLoader.SHATTERED_PLANS_SPRITES = ResourceLoader.create(MessagePumpThread.instance.cacheFiles, masterIndexLoader, ResourceLoader.PageId.SHATTERED_PLANS_SPRITES, false); + ResourceLoader.SHATTERED_PLANS_JPEGS = createResourceLoader(ResourceLoader.PageId.SHATTERED_PLANS_JPEGS); + ResourceLoader.SHATTERED_PLANS_FONTS = createResourceLoader(ResourceLoader.PageId.SHATTERED_PLANS_FONTS); + ResourceLoader.SHATTERED_PLANS_SFX_1 = createResourceLoader(ResourceLoader.PageId.SHATTERED_PLANS_SFX_1); + ResourceLoader.SHATTERED_PLANS_SFX_2 = createResourceLoader(ResourceLoader.PageId.SHATTERED_PLANS_SFX_2); + ResourceLoader.SHATTERED_PLANS_MUSIC_1 = createResourceLoader(ResourceLoader.PageId.SHATTERED_PLANS_MUSIC_1); + ResourceLoader.SHATTERED_PLANS_MUSIC_2 = createResourceLoader(ResourceLoader.PageId.SHATTERED_PLANS_MUSIC_2); + ResourceLoader.SHATTERED_PLANS_STRINGS_2 = createResourceLoader(ResourceLoader.PageId.SHATTERED_PLANS_STRINGS_2); + ResourceLoader.QUICK_CHAT_DATA = createResourceLoader(ResourceLoader.PageId.QUICK_CHAT_DATA); + } + + private static ResourceLoader createResourceLoader(final int extraData2) { + return ResourceLoader.create(masterIndexLoader, MessagePumpThread.instance.cacheFiles, extraData2); + } + + private static void a669pm(final int var1, final int var2, final int var3, final int var4, final int var5) { + _red[_wmc] = var4; + _lgd[_wmc] = _wmc; + _f[_wmc] = var1; + if (_usb < var1) { + _se = var1; + } + + if (_efa > var1) { + _ffu = var1; + } + + _clrzb[_wmc] = var2; + _ajd[_wmc] = var3; + _fy[_wmc] = var5; + final int var6 = var5 + var3 + var2; + final int var7 = var6 != 0 ? 1000 * var2 / var6 : 0; + _gsc[_wmc] = var7; + if (var7 > _se) { + _se = var7; + } + + ++_wmc; + if (_ffu > var7) { + _ffu = var7; + } + + } + + private static String a900es(final Throwable var0) throws IOException { + String var1 = ""; + + final StringWriter var13 = new StringWriter(); + final PrintWriter var3 = new PrintWriter(var13); + var0.printStackTrace(var3); + var3.close(); + final String var4 = var13.toString(); + final BufferedReader var5 = new BufferedReader(new StringReader(var4)); + final String var6 = var5.readLine(); + + while (true) { + final String var8 = var5.readLine(); + if (var8 == null) { + var1 = var1 + "| " + var6; + return var1; + } + + final int var9 = var8.indexOf(40); + final int var10 = var8.indexOf(41, var9 + 1); + String var11; + if (var9 == -1) { + var11 = var8; + } else { + var11 = var8.substring(0, var9); + } + + var11 = var11.trim(); + var11 = var11.substring(var11.lastIndexOf(32) + 1); + var11 = var11.substring(var11.lastIndexOf(9) + 1); + var1 = var1 + var11; + if (var9 != -1 && var10 != -1) { + final int var12 = var8.indexOf(".java:", var9); + if (var12 >= 0) { + var1 = var1 + var8.substring(var12 + 5, var10); + } + } + + var1 = var1 + ' '; + } + } + + private static Boolean j653fr() { + final Boolean var0 = _sad; + _sad = null; + return var0; + } + + private static boolean a351ro() { + final int var1 = s2cPacket.readUByte(); + return var1 == 1; + } + + private static void a599we(final Applet var0) { + final String var1 = var0.getParameter("username"); + if (var1 != null) { + UserIdLoginCredentials.encodeUsername(var1); + } + } + + public static AchievementRequest createAchievementRequest() { + final AchievementRequest var1 = new AchievementRequest(); + achievementRequests.add(var1); + C2SPacket.a093bo(); + return var1; + } + + static void a366vs() { + achievementRequests.forEach(var1 -> C2SPacket.a093bo()); + } + + static void drawLoadingScreen(final String var0, final int var1, final boolean var2) { + try { + final Graphics var5 = canvas.getGraphics(); + if (_haa == null) { + _haa = new java.awt.Font("Helvetica", java.awt.Font.BOLD, 13); + } + + if (var2) { + var5.setColor(Color.black); + var5.fillRect(0, 0, gameWidth, gameHeight); + } + + try { + if (_rma == null) { + _rma = canvas.createImage(304, 34); + } + + final Graphics var6 = _rma.getGraphics(); + var6.setColor(LOADING_SCREEN_PURPLE); + var6.drawRect(0, 0, 303, 33); + var6.fillRect(2, 2, 3 * var1, 30); + var6.setColor(Color.black); + var6.drawRect(1, 1, 301, 31); + var6.fillRect(3 * var1 + 2, 2, 300 - var1 * 3, 30); + var6.setFont(_haa); + var6.setColor(Color.white); + var6.drawString(var0, (-(6 * var0.length()) + 304) / 2, 22); + var5.drawImage(_rma, gameWidth / 2 - 152, gameHeight / 2 - 18, null); + } catch (final Exception var9) { + final int var7 = gameWidth / 2 - 152; + final int var8 = gameHeight / 2 - 18; + var5.setColor(LOADING_SCREEN_PURPLE); + var5.drawRect(var7, var8, 303, 33); + var5.fillRect(2 + var7, 2 + var8, 3 * var1, 30); + var5.setColor(Color.black); + var5.drawRect(1 + var7, var8 + 1, 301, 31); + var5.fillRect(var1 * 3 + var7 + 2, 2 + var8, 300 - 3 * var1, 30); + var5.setFont(_haa); + var5.setColor(Color.white); + var5.drawString(var0, (304 - 6 * var0.length()) / 2 + var7, 22 + var8); + } + } catch (final Exception var10) { + canvas.repaint(); + } + } + + private static void f150com() { + _haa = null; + _rma = null; + } + + public static boolean nextTypedKey() { + synchronized (KeyState.instance) { + if (KeyState.keyTypeQueueFront == _feJ) { + return false; + } else { + //noinspection MagicConstant + lastTypedKeyCode = KeyState.keyTypeCodeQueue[KeyState.keyTypeQueueFront]; + lastTypedKeyChar = KeyState.keyTypeCharQueue[KeyState.keyTypeQueueFront]; + KeyState.keyTypeQueueFront = 1 + KeyState.keyTypeQueueFront & 127; + return true; + } + } + } + + private @NotNull JagexApplet.LoadingStatus serverConnectionFailure(final int errorCode) { + _gbi = 0; + socketMessage2 = null; + serverConnection2 = null; + + final int var2 = this.gamePort2Primary; + this.gamePort2Primary = this.gamePort2Secondary; + this.gamePort2Secondary = var2; + + switch (errorCode) { + case 50 -> pageSource.errorCode = PageSource.ErrorCode.SERVER_CODE_50; + case 51 -> pageSource.errorCode = PageSource.ErrorCode.SERVER_CODE_51; + default -> pageSource.errorCode = PageSource.ErrorCode.UNKNOWN_CONNECTION_FAILURE; + } + + //noinspection NonAtomicOperationOnVolatileField + ++pageSource.failureCount; + if (pageSource.failureCount >= 2 && errorCode == 51) { + return LoadingStatus.ERROR_SERVER_CODE_51; + } else if (pageSource.failureCount >= 2 && errorCode == 50) { + return LoadingStatus.ERROR_SERVER_CODE_50; + } else if (pageSource.failureCount >= 4) { + return LoadingStatus.ERROR_PAGE_SOURCE_MISC; + } else { + return LoadingStatus.OK_PENDING; + } + } + + private @NotNull JagexApplet.LoadingStatus b410u() { + if (pageSource.failureCount < 4) { + try { + if (_gbi == 0) { + socketMessage2 = MessagePumpThread.instance.sendOpenSocketMessage(this.codeHost, this.gamePort2Primary); + ++_gbi; + } + + if (_gbi == 1) { + if (socketMessage2.status == MailboxMessage.Status.FAILURE) { + return this.serverConnectionFailure(-1); + } + if (socketMessage2.status == MailboxMessage.Status.SUCCESS) { + ++_gbi; + } + } + + if (_gbi == 2) { + serverConnection2 = new DuplexStream((Socket) socketMessage2.response, MessagePumpThread.instance); + final Buffer packet = new Buffer(13); + writeHandshake(packet, this.serverId, langId); + packet.writeByte(UPDATE); + packet.writeInt(this.gameCrc); + serverConnection2.write(packet.data, 13); + ++_gbi; + _amCb = 30000L + PseudoMonotonicClock.currentTimeMillis(); + } + + if (_gbi == 3) { + if (serverConnection2.inputAvailable() > 0) { + final int var3 = serverConnection2.readByte(); + if (var3 != 0) { + return this.serverConnectionFailure(var3); + } + + ++_gbi; + } else if (_amCb < PseudoMonotonicClock.currentTimeMillis()) { + return this.serverConnectionFailure(-2); + } + } + + if (_gbi == 4) { + pageSource.initializeServerConnection(serverConnection2); + serverConnection2 = null; + _gbi = 0; + socketMessage2 = null; + return LoadingStatus.OK_COMPLETE; + } else { + return LoadingStatus.OK_PENDING; + } + } catch (final IOException var2) { + return this.serverConnectionFailure(-3); + } + } else { + return switch (pageSource.errorCode) { + case INTEGRITY_CHECK_FAILURE -> LoadingStatus.ERROR_RESOURCE_INTEGRITY_CHECK; + case PROTOCOL_ERROR -> LoadingStatus.ERROR_PAGE_SOURCE_PROTOCOL; + default -> LoadingStatus.ERROR_PAGE_SOURCE_MISC; + }; + } + } + + private @NotNull JagexApplet.LoadingStatus tickIndexLoaders() { + masterIndexLoader.tick(); + if (pageSource.processWork()) { + return LoadingStatus.OK_COMPLETE; + } else { + return this.b410u(); + } + } + + private int a425si(final int var0, final int var1, final e_ var2, final e_ var3, final String var4, final boolean var5) { + final String var6 = var3.a983(); + final String var7 = var2.a983(); + if (serverConnection1 == null) { + final boolean var8 = this.initializeServerConnection(false); + if (!var8) { + return -1; + } + } + + if (loginState == LoginState.SERVER_HANDSHAKE_SUCCESS) { + C2SPacket.buffer.pos = 0; + _sad = null; + if (var4 == null) { + loginPacket.pos = 0; + loginPacket.writeInt(cipherIVGen.nextInt()); + loginPacket.writeInt(cipherIVGen.nextInt()); + loginPacket.writeNullBracketedString(var3.a154() ? var6 : ""); + loginPacket.writeNullBracketedString(var2.a154() ? var7 : ""); + C2SPacket.buffer.writeByte(16); + C2SPacket.buffer.withLengthByte(() -> C2SPacket.buffer.writeEncrypted(loginPacket.data, loginPacket.pos)); + } else { + int var12 = 0; + loginPacket.pos = 0; + if (var5) { + var12 |= 1; + } + + loginPacket.writeInt(cipherIVGen.nextInt()); + loginPacket.writeInt(cipherIVGen.nextInt()); + loginPacket.writeNullBracketedString(var6); + loginPacket.writeNullBracketedString(var7); + loginPacket.writeNullBracketedString(a755ql(var4)); + loginPacket.writeShort(var0); + loginPacket.writeByte(var1); + loginPacket.writeByte(var12); + C2SPacket.buffer.writeByte(18); + C2SPacket.buffer.withLengthShort(() -> { + String var10 = a124ck(getInstance()); + if (var10 == null) { + var10 = ""; + } + + C2SPacket.buffer.writeNullTerminatedString(var10); + C2SPacket.buffer.writeEncrypted(loginPacket.data, loginPacket.pos); + }); + } + + flushC2sPacket(-1); + loginState = LoginState.C6; + } + + if (loginState == LoginState.C6 && s2cBytesAvailable(1)) { + final int var12 = s2cPacket.readUByte(); + s2cPacket.pos = 0; + if (var12 >= 100 && var12 <= 105) { + loginState = LoginState.C3; + _aee = new String[var12 - 100]; + } else { + if (var12 == 248) { + CreateAccountForm.accountCreationFailed(); + _nlc = StringConstants.CREATE_UNABLE; + shutdownServerConnection(); + _kej = false; + return 248; + } + + if (var12 == 99) { + s2cBytesAvailable(1); + _sad = a351ro(); + s2cPacket.pos = 0; + } else { + loginState = LoginState.C4; + ShatteredPlansClient.currentS2cPacketType = var12; + nextS2cPacketLen = -1; + } + } + } + + if (loginState == LoginState.C3) { + final byte var13 = 2; + if (s2cBytesAvailable(var13)) { + final int var9 = s2cPacket.readUShort(); + s2cPacket.pos = 0; + if (s2cBytesAvailable(var9)) { + final int var15 = _aee.length; + + for (int var11 = 0; var15 > var11; ++var11) { + _aee[var11] = s2cPacket.readNullBracketedString(); + } + + shutdownServerConnection(); + _kej = false; + return 100 + var15; + } + } + } + + if (loginState == LoginState.C4 && isS2cPacketFullyRecieved()) { + if (ShatteredPlansClient.currentS2cPacketType == 255) { + final String var14 = s2cPacket.readNullableNullTerminatedString(); + if (var14 != null) { + _cju = var14; + } + } else { + _nlc = s2cPacket.readNullTerminatedString(); + } + + shutdownServerConnection(); + _kej = false; + return ShatteredPlansClient.currentS2cPacketType; + } else { + if (serverConnection1 == null) { + if (_kej) { + if (hasConnectionTimedOut()) { + _nlc = StringConstants.LOGIN_M3; + } else { + _nlc = StringConstants.LOGIN_M2; + } + + _kej = false; + return 249; + } + + final int var12 = this.gamePort1Primary; + this.gamePort1Primary = this.gamePort1Secondary; + this.gamePort1Secondary = var12; + _kej = true; + } + + return -1; + } + } + + private int a968sr(final String var0, final int var1, final int var3, final String var4, final String var5, final boolean var6) { + final e_ var7 = new e_(var0); + final e_ var8 = new e_(var5); + return this.a425si(var1, var3, var8, var7, var4, var6); + } + + private int a031wi(final e_ var0, final e_ var1) { + return this.a425si(0, 0, var0, var1, null, false); + } + + private boolean initializeServerConnection(final boolean var0) { + if (socketMessage1 == null) { + socketMessage1 = MessagePumpThread.instance.sendOpenSocketMessage(this.codeHost, this.gamePort1Primary); + } + + if (socketMessage1.status == MailboxMessage.Status.PENDING) { + return false; + } else { + lastRecievedDataFromServer = lastC2sMessageTimestamp = PseudoMonotonicClock.currentTimeMillis(); + if (socketMessage1.status == MailboxMessage.Status.SUCCESS) { + try { + serverConnection1 = new DuplexStream((Socket) socketMessage1.response, MessagePumpThread.instance); + C2SPacket.buffer.pos = 0; + ShatteredPlansClient.previousS2cPacketType = ShatteredPlansClient.secondPreviousS2cPacketType = ShatteredPlansClient.thirdPreviousS2cPacketType = var0 ? -2 : -1; + loginState = LoginState.SERVER_HANDSHAKE_SUCCESS; + s2cPacket.pos = 0; + writeHandshake(C2SPacket.buffer, this.serverId, langId); + flushC2sPacket(-1); + } catch (final IOException var3) { + loginState = LoginState.SERVER_HANDSHAKE_FAILED; + } + } else { + loginState = LoginState.SERVER_HANDSHAKE_FAILED; + } + + socketMessage1 = null; + return true; + } + } + + private void submitLoginRequest(final LoginCredentials credentials, final boolean isReconnecting) { + cipherIV[0] = cipherIVGen.nextInt(); + cipherIV[1] = cipherIVGen.nextInt(); + cipherIV[2] = (int) (serverCipherIV >> 32); + cipherIV[3] = (int) serverCipherIV; + loginPacket.pos = 0; + loginPacket.writeInt(cipherIV[0]); + loginPacket.writeInt(cipherIV[1]); + loginPacket.writeInt(cipherIV[2]); + loginPacket.writeInt(cipherIV[3]); + writeRandomDat(loginPacket); + loginPacket.writeShort(this.affId); + credentials.writeToPacket(loginPacket); + + C2SPacket.buffer.pos = 0; + C2SPacket.buffer.writeByte(isReconnecting ? 18 : 16); + C2SPacket.buffer.withLengthShort(() -> { + C2SPacket.buffer.writeInt(this.gameCrc); + C2SPacket.buffer.writeLong(this.instanceId); + int flags = 0; + if (this.isMember) { + flags |= 1; + } + if (this.isJagexHost) { + flags |= 8; + } + if (CreateDisplayNameForm._frH != null) { + flags |= 16; + } + + C2SPacket.buffer.writeByte(flags); + String var6 = a124ck(getInstance()); + if (var6 == null) { + var6 = ""; + } + + C2SPacket.buffer.writeNullTerminatedString(var6); + if (CreateDisplayNameForm._frH != null) { + C2SPacket.buffer.writeNullBracketedString(CreateDisplayNameForm._frH); + } + + C2SPacket.buffer.writeEncrypted(loginPacket.data, loginPacket.pos); + }); + flushC2sPacket(-1); + } + + @MagicConstant(valuesFromClass = CommonUI.LoginResult.class) + private int tickLoggingIn(final boolean isReconnecting) { + final String password = CommonUI.getPassword(); + if (serverConnection1 == null) { + if (!this.initializeServerConnection(isReconnecting)) { + return CommonUI.LoginResult.NONE; + } + } + + if (loginState == LoginState.SERVER_HANDSHAKE_SUCCESS) { + if (isReconnecting) { + loginCredentials = createLoginCredentials(null, userId, password); + } else { + loginCredentials = createLoginCredentials(getUsernameOrEmail(), password); + } + + C2SPacket.buffer.pos = 0; + C2SPacket.buffer.writeByte(14); + C2SPacket.buffer.writeByte(loginCredentials.getAuthMode().value); + flushC2sPacket(-1); + loginState = LoginState.C10; + } + + if (loginState == LoginState.C10 && s2cBytesAvailable(1)) { + final int var10 = s2cPacket.readUByte(); + s2cPacket.pos = 0; + if (var10 == 0) { + loginState = LoginState.READY_TO_LOG_IN; + } else { + ShatteredPlansClient.currentS2cPacketType = var10; + loginState = LoginState.C1; + nextS2cPacketLen = -1; + } + } + + if (loginState == LoginState.READY_TO_LOG_IN && s2cBytesAvailable(8)) { + serverCipherIV = s2cPacket.readLong(); + s2cPacket.pos = 0; + this.submitLoginRequest(loginCredentials, isReconnecting); + loginState = LoginState.LOGIN_REQUEST_SENT; + } + + if (loginState == LoginState.LOGIN_REQUEST_SENT && s2cBytesAvailable(1)) { + final int loginResponseCode = s2cPacket.readUByte(); + CreateDisplayNameForm._frH = null; + s2cPacket.pos = 0; + ShatteredPlansClient.currentS2cPacketType = loginResponseCode; + if (loginResponseCode == 0 || loginResponseCode == 1) { + loginState = LoginState.LOGIN_REQUEST_SUCCESSFUL; + nextS2cPacketLen = PacketLengthType.VARIABLE_BYTE_I; + } else { + if (loginResponseCode == 8) { + shutdownServerConnection(); + _kej = false; + return CommonUI.LoginResult.R8; + } + + nextS2cPacketLen = -1; + loginState = LoginState.C1; + } + } + + if (loginState == LoginState.LOGIN_REQUEST_SUCCESSFUL && isS2cPacketFullyRecieved()) { + userId = s2cPacket.readLong(); + lastLoginPassword = password; + adminLevel = s2cPacket.readUByte(); + modLevel = s2cPacket.readUByte(); + membershipLevel = s2cPacket.readUShort(); + final String settings = s2cPacket.readNullableNullTerminatedString(); + final int flags = s2cPacket.readUByte(); + if ((flags & 1) != 0) { + a150ij(); + } + + DobToEnableChatForm._vaj = (flags & 16) != 0; + if (!isReconnecting) { + cannotChat = (flags & 8) != 0; + canOnlyQuickChat = (flags & 2) != 0; + if (cannotChat) { + canOnlyQuickChat = true; + } + } + + playerDisplayName = s2cPacket.readNullTerminatedString(); + normalizedPlayerName = Strings.normalize(playerDisplayName); + CommonUI._tfn = s2cPacket.readUByte(); + loginState = LoginState.LOGGED_IN; + + _kej = false; + if (settings != null) { + _cju = settings; + } + + C2SPacket.buffer.setCipher(new IsaacCipher(cipherIV)); + Arrays.setAll(cipherIV, i -> cipherIV[i] + 50); + s2cPacket.setCipher(new IsaacCipher(cipherIV)); + //noinspection MagicConstant + return ShatteredPlansClient.currentS2cPacketType; + } else if (loginState == LoginState.C1 && isS2cPacketFullyRecieved()) { + shutdownServerConnection(); + if (ShatteredPlansClient.currentS2cPacketType == 7 && !_kej) { + _kej = true; + return CommonUI.LoginResult.NONE; + } else { + if (ShatteredPlansClient.currentS2cPacketType == 7) { + ShatteredPlansClient.currentS2cPacketType = 3; + } + + _nlc = s2cPacket.readNullTerminatedString(); + _kej = false; + //noinspection MagicConstant + return ShatteredPlansClient.currentS2cPacketType; + } + } else { + if (serverConnection1 == null) { + if (_kej) { + if (hasConnectionTimedOut()) { + _nlc = StringConstants.LOGIN_M3; + } else { + _nlc = StringConstants.LOGIN_M2; + } + + _kej = false; + return CommonUI.LoginResult.R3; + } + + final int tmp = this.gamePort1Primary; + this.gamePort1Primary = this.gamePort1Secondary; + this.gamePort1Secondary = tmp; + _kej = true; + } + + return CommonUI.LoginResult.NONE; + } + } + + @Override + public final void init() { + if (instance != null) { + ++reinitializationCount; + if (reinitializationCount >= 3) { + this.redirectToErrorPage("alreadyloaded"); + return; + } + + this.getAppletContext().showDocument(this.getDocumentBase(), "_self"); + return; + } + + try { + this.codeHost = this.getCodeBase().getHost(); + final String codeHostLowerCase = this.codeHost.toLowerCase(); + this.isJagexHost = codeHostLowerCase.equals("jagex.com") || codeHostLowerCase.endsWith(".jagex.com"); + this.gamePort1 = Integer.parseInt(this.getParameter("gameport1")); + this.gamePort2 = Integer.parseInt(this.getParameter("gameport2")); + final String serverIdStr = this.getParameter("servernum"); + if (serverIdStr != null) { + this.serverId = Integer.parseInt(serverIdStr); + } + + this.gameCrc = Integer.parseInt(this.getParameter("gamecrc")); + this.instanceId = Long.parseLong(this.getParameter("instanceid")); + + this.isMember = this.getParameter("member").equals("yes"); + final String langStr = this.getParameter("lang"); + if (langStr != null) { + final int langId = Integer.parseInt(langStr); + JagexApplet.langId = langId >= 5 ? 0 : langId; + } + + final String affIdStr = this.getParameter("affid"); + if (affIdStr != null) { + this.affId = Integer.parseInt(affIdStr); + } + + isSimpleModeEnabled = Boolean.parseBoolean(this.getParameter("simplemode")); + + instance = this; + + gameWidth = ShatteredPlansClient.SCREEN_WIDTH; + gameHeight = ShatteredPlansClient.SCREEN_HEIGHT; + + _eic = JagexBaseApplet.getInstance(); + + MessagePumpThread.instance = new MessagePumpThread(); + final MailboxMessage msg = MessagePumpThread.instance.sendSpawnThreadMessage(this, 1); + assert msg.busyAwait() == MailboxMessage.Status.SUCCESS; + } catch (final Exception e) { + clientError(e, null); + this.redirectToErrorPage("crash"); + } + } + + protected final int tickCommonUI(final boolean alreadyLoggedIn) { + final CommonUI.TickResult action = CommonUI.tick(); + if (action == CommonUI.TickResult.R1) { + final int var5 = this.a031wi(j083bp(), new e_(getUsernameOrEmail(), CommonUI._fjs == Enum1.C3)); + if (var5 != -1) { + a077wo(var5, _aee, _nlc); + _aee = null; + _nlc = null; + } + + final Boolean var6 = j653fr(); + if (var6 != null) { + a813bs(var6); + } + } + + if (action == CommonUI.TickResult.R2) { + final int var5 = this.a968sr(getUsernameOrEmail(), this.affId, _jmt, CommonUI.getPassword(), a983of(), _npm); + if (var5 != -1) { + a453va(_aee, var5, _nlc); + _aee = null; + _nlc = null; + } + } + + if (action == CommonUI.TickResult.LOGGING_IN) { + if (!_qjg.isOk()) { + _qjg = LoadingStatus.OK_PENDING; + a150ea(); + } + + if (alreadyLoggedIn) { + _mdB = false; + } else { + @MagicConstant(valuesFromClass = CommonUI.LoginResult.class) + final int loginResult = this.tickLoggingIn(false); + if (loginResult != CommonUI.LoginResult.NONE) { + if (loginResult == CommonUI.LoginResult.SUCCESS) { + _coo = userId; + CommonUI.handleLoginSucceeded(); + isAnonymous = false; + connectionState = ConnectionState.CONNECTED; + } else { + CommonUI.handleLoginFailed(loginResult, _nlc); + _nlc = null; + } + } + } + } + + if (action == CommonUI.TickResult.R4) { + if (this.isMember) { + sessionId = ""; + navigateToReload(JagexBaseApplet.getInstance()); + } else { + connectionState = ConnectionState.CONNECTED; + isAnonymous = true; + } + } + + if (action == CommonUI.TickResult.TO_SERVER_LIST) { + navigateTo("toserverlist.ws", JagexBaseApplet.getInstance()); + } + + if (action == CommonUI.TickResult.PLAY_FREE_VERSION) { + sessionId = ""; + navigateToReload(JagexBaseApplet.getInstance()); + } + + if (action == CommonUI.TickResult.TO_CUSTOMER_SUPPORT) { + navigateTo("tosupport.ws", JagexBaseApplet.getInstance()); + } + + if (action == CommonUI.TickResult.VIEW_MESSAGES) { + C2SPacket.sendViewMessages(); + } + + if (action == CommonUI.TickResult.RELOAD) { + navigateToReload(JagexBaseApplet.getInstance()); + } + + if (action == CommonUI.TickResult.R12) { + a808bp(CreateAccountForm._cgF, JagexBaseApplet.getInstance()); + } + + if (action == CommonUI.TickResult.TO_LANGUAGE_SELECT) { + try { + if (_vag == null) { + _vag = new r_(MessagePumpThread.instance, new URL(this.getCodeBase(), "countrylist.ws")); + } + + final boolean var9 = _vag.b154(); + if (var9) { + + _vag = null; + } + } catch (final Exception var8) { + clientError(var8, "S1"); + + _vag = null; + } + } + + if (action == CommonUI.TickResult.RETURN_TO_GAME) { + connectionState = ConnectionState.CONNECTED; + } + + if (action == CommonUI.TickResult.QUIT_TO_WEBSITE) { + return 2; + } else { + return 0; + } + } + + private static void navigateTo(final String path, final Applet applet) { + try { + final URL url = new URL(applet.getCodeBase(), path); + applet.getAppletContext().showDocument(a236jg(applet, url), "_top"); + } catch (final Exception var3) { + var3.printStackTrace(); + } + } + + @Override + protected void initialize() { + final Frame frame = new Frame("Jagex"); + frame.pack(); + frame.dispose(); + + this.setBackground(Color.black); + initializeLoadingMessages(langId); + + this.gamePort1Primary = this.gamePort1; + this.gamePort1Secondary = this.gamePort2; + this.gamePort2Primary = this.gamePort1; + this.gamePort2Secondary = this.gamePort2; + + if (MessagePumpThread.instance.cacheFiles.random != null) { + try { + _vca = new BufferedCacheFile(MessagePumpThread.instance.cacheFiles.random, 64); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + + pageSource = new RemotePageSource(); + CacheWorker.instance = CacheWorker.create(MessagePumpThread.instance); + masterIndexLoader = new MasterIndexLoader(pageSource, CacheWorker.instance); + + KeyState.initializeAdditionalCodeMappings(); + attachToCanvas(JagexBaseApplet.canvas); + } + + protected final void mgsPacketHandler() { + final int packetId = ShatteredPlansClient.currentS2cPacketType; + + if (packetId < 64 && S2CPacket.MGS_ENABLED[packetId]) { + switch (packetId) { + case S2CPacket.Type.KEEPALIVE: + return; + case S2CPacket.Type.XTEA: + shutdownServerConnection(); + break; + case S2CPacket.Type.HISCORE: + handleHiscorePacket(s2cPacket); + break; + case S2CPacket.Type.ACHIEVEMENTS: + handleAchievementsPacket(s2cPacket); + break; + case S2CPacket.Type.LEVEL_PROGRESS: + handleLevelPacket(); + break; + case S2CPacket.Type.PROFILE: + handleProfilePacket(s2cPacket); + break; + case S2CPacket.Type.RATINGS: + a423r(); + break; + case S2CPacket.Type.SESSION_ID: + sessionId = s2cPacket.readNullTerminatedString(); + break; + case S2CPacket.Type.REFLECT: + ReflectionRequest.recieve(MessagePumpThread.instance, s2cPacket); + break; + case S2CPacket.Type.CHAT: + case S2CPacket.Type.QUICK_CHAT: + a681nc(receiveChatMessage(packetId == S2CPacket.Type.QUICK_CHAT, s2cPacket)); + break; + case S2CPacket.Type.SOCIAL: + PlayerListEntry.handleSocialPacket(s2cPacket); + break; + case S2CPacket.Type.DISPLAY_NAME: + setPlayerDisplayName(s2cPacket.readNullTerminatedString()); + break; + case S2CPacket.Type.SHOW_DOCUMENT: + this.handleShowDocumentPacket(); + break; + case S2CPacket.Type.DISABLE_CHAT_RESTRICTIONS: + handleDisableChatRestrictionsPacket(); + break; + default: + clientError(null, "MGS1: " + a738w()); + shutdownServerConnection(); + break; + } + } else { + clientError(null, "MGS2: " + a738w()); + shutdownServerConnection(); + } + } + + protected final void a540(final boolean var1) { + processKeyState(); + processMouseState(); + mouseWheelRotation = MouseWheelState.instance.poll(); + assert !isConnectedAndLoaded() || connectionState == ConnectionState.RECONNECTING || ShatteredPlansClient.fullScreenCanvas == null || !ShatteredPlansClient.fullScreenCanvas.focusWasLost; + + if (connectedAndLoggedIn()) { + if (KeyState.ticksSinceLastKeyEvent > IDLE_TICKS && MouseState.ticksSinceLastMouseEvent > IDLE_TICKS) { + shutdownServerConnection(); + CommonUI.handleServerDisconnect(); + CommonUI.handleLoginFailed(CommonUI.LoginResult.R2, StringConstants.IDLE_MESSAGE_20_MIN); + _mdB = true; + _ipb = 15000L + PseudoMonotonicClock.currentTimeMillis(); + } + } + + + if (_qjg == LoadingStatus.OK_PENDING || _qjg == LoadingStatus.OK_COMPLETE) { + final boolean var6 = _qjg == LoadingStatus.OK_PENDING; + _qjg = this.tickIndexLoaders(); + if (var6 && _qjg == LoadingStatus.OK_COMPLETE && connectionState == ConnectionState.RECONNECTING && !f154jc()) { + CommonUI.handleLoginSucceeded(); + } + + if (!_qjg.isOk()) { + _ipb = PseudoMonotonicClock.currentTimeMillis() + 15000L; + } + } + + if (!_qjg.isOk()) { + if (loadStage < LoadStage.REQUEST_GAME_STRINGS) { + switch (_qjg) { + case ERROR_SERVER_CODE_51 -> this.redirectToErrorPage("js5connect_full"); + case ERROR_RESOURCE_INTEGRITY_CHECK -> this.redirectToErrorPage("js5crc"); + case ERROR_PAGE_SOURCE_PROTOCOL -> this.redirectToErrorPage("js5io"); + case ERROR_SERVER_CODE_50 -> this.redirectToErrorPage("outofdate"); + default -> this.redirectToErrorPage("js5connect"); + } + } else if (connectionState >= ConnectionState.CONNECTED) { + CommonUI.handleServerDisconnect(); + switch (_qjg) { + case ERROR_SERVER_CODE_51 -> CommonUI.handleLoginFailed(CommonUI.LoginResult.R256, StringConstants.ERROR_JS5CONNECT_FULL); + case ERROR_RESOURCE_INTEGRITY_CHECK -> CommonUI.handleLoginFailed(CommonUI.LoginResult.R256, StringConstants.ERROR_JS5CRC); + case ERROR_PAGE_SOURCE_PROTOCOL -> CommonUI.handleLoginFailed(CommonUI.LoginResult.R256, StringConstants.COMM_IO_ERROR); + case ERROR_SERVER_CODE_50 -> CommonUI.handleLoginFailed(CommonUI.LoginResult.R5, StringConstants.LOGIN_GAME_UPDATED); + default -> CommonUI.handleLoginFailed(CommonUI.LoginResult.R256, StringConstants.ERROR_JS5_CONNECT); + } + + _mdB = true; + } + } + + if ((!_qjg.isOk() || f154jc()) && _ipb <= PseudoMonotonicClock.currentTimeMillis()) { + _mdB = false; + if (!_qjg.isOk()) { + _qjg = LoadingStatus.OK_PENDING; + a150ea(); + } + } + + if (_qjg == LoadingStatus.OK_COMPLETE && !f154jc()) { + CommonUI.loadingFailed = false; + } + + if (loadStage == LoadStage.LOAD_MASTER_INDEX && masterIndexLoader.loadIndex()) { + loadStage = LoadStage.REQUEST_COMMON_DATA; + } + + if (loadStage == LoadStage.REQUEST_COMMON_DATA) { + if (langId != 0) { + ResourceLoader.COMMON_STRINGS = createResourceLoader(ResourceLoader.PageId.COMMON_STRINGS); + } + + ResourceLoader.COMMON_SPRITES = createResourceLoader(ResourceLoader.PageId.COMMON_SPRITES); + ResourceLoader.COMMON_FONTS = createResourceLoader(ResourceLoader.PageId.COMMON_FONTS); + ResourceLoader.JAGEX_LOGO_ANIMATION = createResourceLoader(ResourceLoader.PageId.JAGEX_LOGO_ANIMATION); + loadStage = LoadStage.LOAD_COMMON_STRINGS; + } + + if (loadStage == LoadStage.LOAD_COMMON_STRINGS) { + if (ResourceLoader.COMMON_STRINGS != null && ResourceLoader.COMMON_STRINGS.isIndexLoaded()) { + if (!ResourceLoader.COMMON_STRINGS.hasGroup("")) { + ResourceLoader.COMMON_STRINGS = null; + } else if (ResourceLoader.COMMON_STRINGS.loadGroupData("")) { + StringConstants.loadCommon(ResourceLoader.COMMON_STRINGS); + ResourceLoader.COMMON_STRINGS = null; + ShatteredPlansClient.resetFrameClock(); + } + } + + if (ResourceLoader.COMMON_STRINGS == null) { + loadStage = LoadStage.LOAD_COMMON_DATA; + } + } + + if (loadStage == LoadStage.LOAD_COMMON_DATA && isCommonUiLoaded(ResourceLoader.COMMON_SPRITES, ResourceLoader.COMMON_FONTS, ResourceLoader.JAGEX_LOGO_ANIMATION) && ResourceLoader.JAGEX_LOGO_ANIMATION.loadAllGroups()) { + f150com(); + CommonUI.setLoadProgress(0, StringConstants.LOADING); + CommonUI.load(ResourceLoader.COMMON_SPRITES, ResourceLoader.COMMON_FONTS, ResourceLoader.JAGEX_LOGO_ANIMATION); + + if (isSimpleModeEnabled) { + CommonUI.a423oo(); + } + + JagexLogoIntroAnimation.load(ResourceLoader.JAGEX_LOGO_ANIMATION); + ResourceLoader.JAGEX_LOGO_ANIMATION = null; + a599we(this); + ShatteredPlansClient.resetFrameClock(); + loadStage = LoadStage.REQUEST_GAME_STRINGS; + } + + if (loadStage == LoadStage.REQUEST_GAME_STRINGS) { + if (langId != 0) { + ResourceLoader.SHATTERED_PLANS_STRINGS_1 = createResourceLoader(ResourceLoader.PageId.SHATTERED_PLANS_STRINGS_1); + } + loadStage = LoadStage.LOAD_GAME_STRINGS; + } + + if (loadStage == LoadStage.LOAD_GAME_STRINGS) { + if (ResourceLoader.SHATTERED_PLANS_STRINGS_1 == null || ResourceLoader.SHATTERED_PLANS_STRINGS_1.isIndexLoaded() && ResourceLoader.SHATTERED_PLANS_STRINGS_1.loadAllGroups()) { + loadStage = LoadStage.REQUEST_GAME_DATA; + } else { + CommonUI.setLoadProgress(0.0F, ShatteredPlansClient.loadingMessage(ResourceLoader.SHATTERED_PLANS_STRINGS_1, waitingForTextMessage, loadingTextMessage)); + } + } + + if (loadStage == LoadStage.REQUEST_GAME_DATA) { + initializeGameResourceLoaders(); + loadStage = LoadStage.LOADED; + } + + if (!var1 && JagexBaseApplet._ncc) { + detachFromCanvas(JagexBaseApplet.canvas); + this.initializeCanvas(); + attachToCanvas(JagexBaseApplet.canvas); + } + + if (S2CPacket.MGS_ENABLED[8]) { + handlePendingReflectionRequests(); + } + } + + protected final void j423() { + if (loadStage >= LoadStage.REQUEST_GAME_STRINGS) { + if (!JagexLogoIntroAnimation.isFinished()) { + JagexLogoIntroAnimation.tick(); + } else if (connectionState == ConnectionState.NOT_CONNECTED) { + this.tickCommonUI(false); + } else { + CommonUI.tick(); + } + } + } + + @MagicConstant(valuesFromClass = CommonUI.LoginResult.class) + protected final int tickReconnecting() { + if (this.didHandleError || !f154jc() || _mdB) { + return CommonUI.LoginResult.NONE; + } + @MagicConstant(valuesFromClass = CommonUI.LoginResult.class) + final int var2 = this.tickLoggingIn(true); + if (var2 == CommonUI.LoginResult.NONE) { + return CommonUI.LoginResult.NONE; + } + if (var2 == CommonUI.LoginResult.SUCCESS || var2 == CommonUI.LoginResult.R1) { + if (connectionState == ConnectionState.RECONNECTING && _qjg == LoadingStatus.OK_COMPLETE) { + CommonUI.handleLoginSucceeded(); + } + } else { + if (!_vmNb) { + this.redirectToErrorPage("reconnect"); + } + CommonUI.handleServerDisconnect(); + CommonUI.handleLoginFailed(var2, _nlc); + _mdB = true; + _ipb = PseudoMonotonicClock.currentTimeMillis() + 15000L; + } + return var2; + } + + private void handleShowDocumentPacket() { + final int len = nextS2cPacketLen - 1; + final byte[] data = new byte[len]; + s2cPacket.readCipheredBytes(data, len); + showDocument(JagexBaseApplet.getInstance(), Strings.decode1252String(data)); + } + + @SuppressWarnings("WeakerAccess") + protected static final class LoadStage { + public static final int LOAD_MASTER_INDEX = 0; + public static final int REQUEST_COMMON_DATA = 1; + public static final int LOAD_COMMON_STRINGS = 2; + public static final int LOAD_COMMON_DATA = 3; + public static final int REQUEST_GAME_STRINGS = 10; + public static final int LOAD_GAME_STRINGS = 11; + public static final int REQUEST_GAME_DATA = 12; + public static final int LOADED = 20; + } + + @SuppressWarnings("WeakerAccess") + public static final class ConnectionState { + public static final int NOT_CONNECTED = 0; + public static final int CONNECTED = 10; + public static final int RECONNECTING = 11; + } + + private enum LoadingStatus { + OK_PENDING(true), + OK_COMPLETE(true), + ERROR_PAGE_SOURCE_MISC(false), + ERROR_PAGE_SOURCE_PROTOCOL(false), + ERROR_RESOURCE_INTEGRITY_CHECK(false), + ERROR_SERVER_CODE_51(false), + ERROR_SERVER_CODE_50(false); + + private final boolean isOk; + + LoadingStatus(final boolean isOk) { + this.isOk = isOk; + } + + @SuppressWarnings({"WeakerAccess", "BooleanMethodIsAlwaysInverted"}) + public boolean isOk() { + return this.isOk; + } + } +} diff --git a/src/main/java/funorb/shatteredplans/client/MailboxMessage.java b/src/main/java/funorb/shatteredplans/client/MailboxMessage.java new file mode 100644 index 0000000..51151a6 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/MailboxMessage.java @@ -0,0 +1,59 @@ +package funorb.shatteredplans.client; + +import funorb.client.JagexBaseApplet; +import org.intellij.lang.annotations.MagicConstant; + +public final class MailboxMessage { + @MagicConstant(valuesFromClass = Status.class) + public volatile int status = 0; + public int ipayload1; + public volatile Object response; + public MailboxMessage next; + @MagicConstant(valuesFromClass = Type.class) + public + int type; + public Object opayload; + public int ipayload2; + + /** + * Busy-waits until {@link #status} is no longer {@link Status#PENDING}. + * + * @return the final status + */ + @MagicConstant(intValues = {Status.SUCCESS, Status.FAILURE}) + public int busyAwait() { + while (this.status == Status.PENDING) { + JagexBaseApplet.maybeSleep(10L); + } + //noinspection MagicConstant + return this.status; + } + + public static final class Status { + public static final int PENDING = 0; + public static final int SUCCESS = 1; + public static final int FAILURE = 2; + } + + public static final class Type { + public static final int OPEN_SOCKET = 1; + public static final int SPAWN_THREAD = 2; + public static final int DNS_REVERSE_LOOKUP = 3; + public static final int OPEN_URL_STREAM = 4; + public static final int LIST_DISPLAY_MODES = 5; + public static final int ENTER_FULL_SCREEN = 6; + public static final int EXIT_FULL_SCREEN = 7; + public static final int GET_DECLARED_METHOD = 8; + public static final int GET_DECLARED_FIELD = 9; + public static final int OPEN_GAME_PREFERENCES_CACHE = 12; + public static final int OPEN_GLOBAL_PREFERENCES_CACHE = 13; + public static final int MOVE_MOUSE = 14; + public static final int SHOW_CURSOR = 15; + public static final int WINDOWS_START = 16; + public static final int SET_CUSTOM_CURSOR = 17; + public static final int GET_CLIPBOARD = 18; + public static final int SET_CLIPBOARD = 19; + public static final int DNS_LOOKUP = 21; + public static final int A287 = 22; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/Menu.java b/src/main/java/funorb/shatteredplans/client/Menu.java new file mode 100644 index 0000000..5ba06c3 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/Menu.java @@ -0,0 +1,3159 @@ +package funorb.shatteredplans.client; + +import funorb.Strings; +import funorb.awt.FullScreenCanvas; +import funorb.awt.KeyState; +import funorb.awt.MouseState; +import funorb.client.JagexBaseApplet; +import funorb.client.MenuInputState; +import funorb.client.RankingsRequest; +import funorb.client.lobby.vm_; +import funorb.graphics.ArgbSprite; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.graphics.NineSliceSprite; +import funorb.graphics.PalettedSpriteFont; +import funorb.graphics.Sprite; +import funorb.graphics.mq_; +import funorb.shatteredplans.C2SPacket; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.game.ClientGameSession; +import funorb.shatteredplans.client.game.GameView; +import funorb.shatteredplans.client.ui.FloatingPanel; +import funorb.shatteredplans.game.GameOptions; +import funorb.shatteredplans.game.GameState.GameType; +import funorb.util.MathUtil; +import funorb.util.PseudoMonotonicClock; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NotNull; + +import java.awt.Frame; +import java.util.ArrayDeque; +import java.util.Objects; +import java.util.Queue; +import java.util.stream.IntStream; + +public final class Menu { + private static final int[] MEMBERS_PAUSE_MENU_MULTIPLAYER_ITEMS_1 = {Item.RETURN_TO_GAME, Item.SOUND_VOLUME, Item.MUSIC_VOLUME, Item.FULLSCREEN, Item.INSTRUCTIONS_2, 11, Item.RESIGN, Item.RETURN_TO_LOBBY}; + private static final int[] MEMBERS_PAUSE_MENU_MULTIPLAYER_ITEMS_2 = new int[]{Item.RETURN_TO_GAME, Item.SOUND_VOLUME, Item.MUSIC_VOLUME, Item.FULLSCREEN, Item.INSTRUCTIONS_2, 13, Item.RETURN_TO_LOBBY}; + private static final int[] MEMBERS_PAUSE_MENU_MULTIPLAYER_ITEMS_3 = new int[]{Item.RETURN_TO_GAME, Item.SOUND_VOLUME, Item.MUSIC_VOLUME, Item.FULLSCREEN, Item.INSTRUCTIONS_2, Item.RETURN_TO_LOBBY}; + public static final int[] _emc = new int[4]; + public static final Menu[] menus = new Menu[14]; + public static final Queue rankingsRequests = new ArrayDeque<>(); + private static final int[] _vnr = new int[6]; + private static final int[] _ndd = new int[]{1, 1, 2, 2, 3, 1, 3, 2, 2, 2, 3, 3, 1, 3, 5, 5, 5, 5, 3, 5, 3, 5, 1, 1, 5}; + public static final int[] _pmDb = new int[4]; + private static final int[] _eig = new int[]{100, 100, 200, 200, 300, 100, 300, 200, 200, 200, 300, 300, 100, 300, 500, 500, 500, 500, 300, 500, 300, 500, 100, 100, 500}; + private static final int[] _kcm = new int[4]; + private static final int[] _sf = new int[4]; + private static final int[] MEMBERS_PAUSE_MENU_SINGLEPLAYER_ITEMS = {Item.RETURN_TO_GAME, Item.SOUND_VOLUME, Item.MUSIC_VOLUME, Item.FULLSCREEN, Item.INSTRUCTIONS_2, Item.END_GAME}; + private static final int[] RATINGS_MENU_ITEMS = {Item.RATING_MODE_1, Item.RATING_MODE_2, Item.CURRENT_MENU}; + private static final int[] ACHIEVEMENTS_MENU_ITEMS = {Item.CURRENT_MENU}; + private static final int RED = 0xff0000; + private static final String[] BROKEN_LINES_LOGIN = new String[16]; + private static final MenuInputState _nsnb = new MenuInputState(1); + private static final String[] _tsK = new String[16]; + static final MenuInputState _gsl = new MenuInputState(1); + public static Sprite SHINE_LEFT; + public static Sprite SHINE_RIGHT; + public static Sprite SHINE_MID; + public static int _hgt; + private static int _ffy; + private static int _kbA; + private static int[] _kbD; + private static int _acw; + private static int _qBb; + private static int[] _erq; + private static int _os; + public static Sprite _ok; + public static PalettedSpriteFont FONT; + @MagicConstant(valuesFromClass = Item.class) + private static final int[][] items = new int[14][]; + private static final int[] _tvcr = new int[14]; + private static final int[] _tvct = new int[14]; + private static final int[] widths = new int[14]; + private static final int[] _tvcm = new int[14]; + public static GameOptions gameOptions; + public static Sprite MENU_HEX; + public static Sprite INSTR_MAIN_VIEW; + public static Sprite INSTR_STAR_FRAME; + public static PalettedSpriteFont SMALL_FONT; + public static Sprite ORB_COIN; + public static Sprite[] ACHIEVEMENTS; + public static Sprite[] _gvsb; + public static Sprite[] _vha; + public static Sprite[] ACHIEVEMENT_ICONS; + public static int unlockedAchievementsBitmap; + @MagicConstant(valuesFromClass = Id.class) + public static int currentMenu; + @MagicConstant(valuesFromClass = Id.class) + public static int nextMenu; + public static int _ehQ; + public static Sprite[] _kjf; + private static int[] _oob; + private static int _anc; + private static RankingsRequest _riI = null; + public static boolean discarding; + private static int _upd; + private static int _tvcq = 0; + private static Sprite _ilgb = null; + private static int _nba; + private static int _mgfb; + private static final int[] _ssH = new int[StringConstants.INSTRUCTIONS_TABNAMES.length]; + public static @NotNull GameType skirmishGameType = GameType.CONQUEST; + private static int _leb; + private static int[] _cbi; + private static int _sbe; + private static Sprite _glh = null; + private static int _ekA; + @MagicConstant(valuesFromClass = Id.class) + private static int _brm; + private static int _cleo; + private static int _nct = 0; + private static int _onc; + public static boolean areAchievementsOffline; + private static int[] _fgc; + private static int _c; + private static int[] _py; + static int _ahR; + static int _ldj; + static int _rnb; + static boolean isLobbyDialogOpen = false; + private static String[] _tc; + private static int _vob; + static long _brp; + static int _hoa; + static int[] _ssa; + static int _uqk; + static int _dmra; + static String[] _hmp; + static String[] _kpo; + static String[] _kdb; + static boolean isFullscreenDialogOpen = false; + static int _dbf; + static String[] _nld; + static String[] _tuef; + static DialogOption[] _E; + static @NotNull Menu.FullscreenDialog currentFullscreenDialog = FullscreenDialog.MEMBERS_ONLY_NOT_LOGGED_IN; + static NineSliceSprite buttonSprite; + @MagicConstant(valuesFromClass = Id.class) + private final int id; + private final MenuInputState inputState; + private int _g; + private boolean _f; + private int _h; + private int _i; + static { + final int[] var0 = new int[]{150, 60, 60, 60, 60, 60}; + int var1 = 560; + + int var2; + for (var2 = 0; var2 < 6; ++var2) { + var1 -= var0[var2]; + } + + var2 = 560; + + for (int var3 = 5; var3 > 0; --var3) { + final int var4 = var1 / (2 + var3); + var1 -= var4; + var2 -= var4; + _vnr[var3] = var2 - (var0[var3] >> 1); + var2 -= var0[var3]; + } + + _vnr[0] = var1 >> 1; + + register(Id.MAIN, 0, 400, 200, new int[]{Item.TUTORIAL, Item.SINGLE_PLAYER_SKIRMISH, Item.ENTER_MULTIPLAYER_LOBBY, Item.INSTRUCTIONS_1, Item.OPTIONS_MENU, Item.RANKINGS, Item.ACHIEVEMENTS, Item.QUIT}); + register(Id.PAUSE_SINGLEPLAYER, 0, 320, 150, new int[]{Item.RETURN_TO_GAME, Item.SOUND_VOLUME, Item.MUSIC_VOLUME, Item.INSTRUCTIONS_2, Item.END_GAME}); + register(Id.PAUSE_MULTIPLAYER_1, 0, 320, 150, new int[]{Item.RETURN_TO_GAME, Item.SOUND_VOLUME, Item.MUSIC_VOLUME, Item.INSTRUCTIONS_2, 11, Item.RESIGN, Item.RETURN_TO_LOBBY}); + register(Id.PAUSE_MULTIPLAYER_2, 0, 370, 150, new int[]{Item.RETURN_TO_GAME, Item.SOUND_VOLUME, Item.MUSIC_VOLUME, Item.INSTRUCTIONS_2, 13, Item.RETURN_TO_LOBBY}); + register(Id.PAUSE_MULTIPLAYER_3, 0, 320, 150, new int[]{Item.RETURN_TO_GAME, Item.SOUND_VOLUME, Item.MUSIC_VOLUME, Item.INSTRUCTIONS_2, Item.RETURN_TO_LOBBY}); + register(Id.RATINGS, 0, 400, 380, new int[]{Item.LOGIN_CREATE_ACCOUNT, Item.CURRENT_MENU}); + register(Id.INSTRUCTIONS_1, 320, 500, 70, new int[]{Item.TUTORIAL, Item.CURRENT_MENU}); + register(Id.INSTRUCTIONS_2, 320, 500, 50, new int[]{Item.CURRENT_MENU}); + register(Id.ACHIEVEMENTS, 0, 500, 400, new int[]{Item.LOGIN_CREATE_ACCOUNT, Item.CURRENT_MENU}); + register(Id.G9, 0, 500, 200, new int[]{Item.LOGIN_CREATE_ACCOUNT, Item.DISCARD}); + register(Id.ERROR, 0, 320, 400, new int[]{Item.MENU}); + register(Id.SKIRMISH_SETUP, 0, 500, 200, new int[]{Item.START_SKIRMISH, Item.GAME_TYPE, Item.RULE_SET, Item.CURRENT_MENU}); + register(Id.OPTIONS, 0, 400, 200, new int[]{Item.SOUND_VOLUME, Item.MUSIC_VOLUME, Item.MUSIC_TRACK, Item.FULLSCREEN, Item.WATCH_INTRODUCTION, Item.CURRENT_MENU}); + } + + public Menu(@MagicConstant(valuesFromClass = Id.class) final int id) { + this.id = id; + this.inputState = new MenuInputState(items[this.id].length); + this.a126(false); + } + + private static Sprite a367(final int var0) { + Sprite var2 = _vha[var0]; + if (var2 == null) { + _vha[var0] = var2 = new Sprite(64, 64); + Drawing.saveContext(); + var2.installForDrawing(); + achievementIcon(var0).draw(16, 16); + Drawing.b669(3, 3, 64, 64); + Drawing.restoreContext(); + } + + return var2; + } + + private static void c487() { + if (Sounds.soundVolume > 32) { + int var1 = Sounds.soundVolume % 32; + if (var1 == 0) { + var1 = 32; + } + + Sounds.setSoundVolume(Sounds.soundVolume - var1); + } else { + Sounds.setSoundVolume(0); + } + } + + public static void drawShine(final int x, final int y, final int width, final int height) { + drawShine(x, y, width, height, 0x3ca4a7); + } + + private static void register(@MagicConstant(valuesFromClass = Id.class) final int id, + final int var1, + final int var2, + final int var4, + final int[] var3) { + _tvcr[id] = var2; + _tvcm[id] = var4; + widths[id] = 25; + _tvct[id] = var1; + items[id] = var3; + } + + public static void switchTo(@MagicConstant(valuesFromClass = Id.class) final int id, final int var0, final boolean var2) { + if (nextMenu != id) { + nextMenu = id; + _brm = var0; + if (nextMenu >= 0) { + menus[nextMenu]._g = -1; + menus[nextMenu].a126(var2); + } + _ehQ = 0; + } + } + + private static void c487hd() { + final int var0 = _ssH.length; + _kbA = 0; + _cbi = new int[var0]; + + for (int var1 = 0; var0 > var1; ++var1) { + int var2 = a353aa(var1); + if (var1 != var0 - 1) { + var2 += 50; + } + + _cbi[var1] = var2; + _kbA += var2; + } + + _kbA -= 294; + } + + public static void a487ai() { + double var0 = Math.PI * (double) (ShatteredPlansClient.currentTick % 512) / 256.0D; + final int var2 = 16 * (GameUI.FACTION_RING.width / 2 - 9); + _emc[0] = (int) ((double) var2 * Math.sin(var0)); + _pmDb[0] = (int) (Math.cos(var0) * (double) var2); + _emc[1] = -_emc[0]; + _pmDb[1] = -_pmDb[0]; + var0 += 2.0943951023931953D; + _emc[2] = (int) (Math.sin(var0) * (double) var2); + _pmDb[2] = (int) ((double) var2 * Math.cos(var0)); + var0 += 2.0943951023931953D; + _emc[3] = (int) (Math.sin(var0) * (double) var2); + _pmDb[3] = (int) (Math.cos(var0) * (double) var2); + } + + private static void a150mgf() { + if (Sounds.musicVolume < 224) { + final int var0 = Sounds.musicVolume % 32; + Sounds.setMusicVolume(Sounds.musicVolume + (32 - var0)); + } else { + Sounds.setMusicVolume(256); + } + } + + public static int get_idb() { + return FONT.capHeight + FONT.descent; + } + + private static Sprite a367dmr(final int var0) { + Sprite var1 = _gvsb[var0]; + if (var1 == null) { + _gvsb[var0] = var1 = new Sprite(256, 256); + Drawing.saveContext(); + var1.installForDrawing(); + ACHIEVEMENTS[var0].draw(64, 64); + Drawing.b669(12, 12, 256, 256); + Drawing.restoreContext(); + } + + return var1; + } + + private static void a713ir(int var0, int var1, int var2, final int var3) { + if (Drawing.left <= var1 && var1 < Drawing.right) { + if (Drawing.top > var2) { + var0 += var2 - Drawing.top; + var2 = Drawing.top; + } + + if (Drawing.bottom < var0 + var2) { + var0 = -var2 + Drawing.bottom; + } + + for (int var5 = var1 + Drawing.width * var2; var0 > 0; --var0) { + var1 = Drawing.screenBuffer[var5]; + var2 = var3 + var1; + final int var4 = (var3 & 16711935) + (var1 & 16711935); + var1 = (var4 & 16777472) + (65536 & var2 - var4); + final int var01 = -(var1 >>> 8) + var1; + final int var11 = -var1 + var2; + Drawing.screenBuffer[var5] = var01 | var11; + var5 += Drawing.width; + } + + } + } + + private static RankingsRequest a250jba() { + return rankingsRequests.stream() + .filter(var3 -> var3._k == 0).findFirst() + .orElseGet(() -> { + final RankingsRequest var3 = new RankingsRequest(); + var3._k = 0; + var3._j = 10; + rankingsRequests.add(var3); + C2SPacket.a970uf(var3); + return var3; + }); + } + + private static int a353aa(final int var0) { + final int var3 = 1 + SMALL_FONT.ascent * 3 / 4; + final int var4 = _tvcr[6] - 60; + final byte var5 = 40; + int var6; + int var7; + if (var0 == 0) { + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(StringConstants.TEXT_INSTRUCTIONS_0), SMALL_FONT, new int[]{var4}); + var7 = var5 + var6 * var3; + } else if (var0 == 1) { + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(StringConstants.TEXT_INSTRUCTIONS_GLOSSARY_1), SMALL_FONT, new int[]{var4}); + var7 = var5 + var3 * var6; + } else if (var0 == 2) { + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(StringConstants.TEXT_INSTRUCTIONS_GLOSSARY_2), SMALL_FONT, new int[]{var4}); + var7 = var5 + var3 * var6; + } else { + if (var0 == 3) { + return 294; + } + + if (var0 == 4) { + return 294; + } + + String var2; + if (var0 == 5) { + var2 = StringConstants.TEXT_INSTRUCTIONS_PLACEMENT; + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(var2), SMALL_FONT, new int[]{var4 - 80}); + var7 = var5 + (var3 * (3 + 4 * var6) >> 2); + var2 = StringConstants.TEXT_INSTRUCTIONS_MOVEMENT; + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(var2), SMALL_FONT, new int[]{var4 - 80}); + var2 = StringConstants.TEXT_INSTRUCTIONS_PROJECTS; + var7 += (var6 * 4 + 3) * var3 >> 2; + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(var2), SMALL_FONT, new int[]{var4 - 80}); + var7 += var6 * var3; + } else if (var0 == 6) { + var2 = StringConstants.TEXT_INSTRUCTIONS_FLEETSIZE; + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(var2), SMALL_FONT, new int[]{var4 - 80}); + var2 = StringConstants.TEXT_INSTRUCTIONS_END_TURN; + var7 = var5 + (var3 * (3 + 4 * var6) >> 2); + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(var2), SMALL_FONT, new int[]{var4 - 80}); + var2 = StringConstants.TEXT_INSTRUCTIONS_HOTKEYS; + var7 += (var6 * 4 + 3) * var3 >> 2; + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(var2), SMALL_FONT, new int[]{var4 - 80}); + var2 = StringConstants.TEXT_INSTRUCTIONS_STATS; + var7 += (4 * var6 + 3) * var3 >> 2; + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(var2), SMALL_FONT, new int[]{var4 - 80}); + var7 += var6 * var3; + } else if (var0 == 7) { + var2 = StringConstants.TEXT_INSTRUCTIONS_ANIMATION; + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(var2), SMALL_FONT, new int[]{var4 - 80}); + final short var8 = 294; + var7 = var8 + var3 * (var6 - 3); + } else if (var0 == 8) { + var2 = StringConstants.TEXT_INSTRUCTIONS_PROJECT_METAL; + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(var2), SMALL_FONT, new int[]{var4 - 40}); + var2 = StringConstants.TEXT_INSTRUCTIONS_PROJECT_BIOMASS; + var7 = var5 + ((3 + var6 * 4) * var3 >> 2); + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(var2), SMALL_FONT, new int[]{var4 - 40}); + var7 += (4 * var6 + 3) * var3 >> 2; + var2 = StringConstants.TEXT_INSTRUCTIONS_PROJECT_ENERGY; + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(var2), SMALL_FONT, new int[]{var4 - 40}); + var2 = StringConstants.TEXT_INSTRUCTIONS_PROJECT_EXOTICS; + var7 += (4 * var6 + 3) * var3 >> 2; + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(var2), SMALL_FONT, new int[]{var4 - 40}); + var7 += var6 * var3; + var7 += var3; + } else { + if (var0 == 9) { + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(StringConstants.TEXT_INSTRUCTIONS_GAME_TYPE), SMALL_FONT, new int[]{var4}); + } else { + if (var0 != 10) { + throw new RuntimeException(); + } + + var6 = GameUI.breakLines(ShatteredPlansClient.templateDictionary.expand(StringConstants.TEXT_INSTRUCTIONS_CLASSIC), SMALL_FONT, new int[]{var4}); + } + var7 = var5 + var6 * var3; + } + } + + return Math.max(var7, 294); + } + + private static void a587oa() { + int var0 = ShatteredPlansClient.SCREEN_HEIGHT; + int var1 = 0; + int var2 = ShatteredPlansClient.SCREEN_WIDTH; + final int var3 = 0; + + if (Drawing.height < var0 + var3) { + var0 = Drawing.height - var3; + } + + if (Drawing.width < var2 + var1) { + var2 = Drawing.width - var1; + } + + --var1; + final int var4 = var0 + var3; + + for (int var5 = var3; var4 > var5; ++var5) { + int var7 = var1 + Drawing.width * var5; + + for (int var8 = var2; var8 > 0; --var8) { + ++var7; + int var9 = Drawing.screenBuffer[var7]; + var9 = (var9 >> 2 & 4144959) + (8355711 & var9 >> 1); + Drawing.screenBuffer[var7] = var9; + } + } + + } + + private static void f423cc() { + final int var1; + if (Sounds.soundVolume >= 224) { + Sounds.setSoundVolume(256); + } else { + var1 = Sounds.soundVolume % 32; + Sounds.setSoundVolume(-var1 + 32 + Sounds.soundVolume); + } + + } + + private static void d487qs() { + if (Sounds.musicVolume > 32) { + int var1 = Sounds.musicVolume % 32; + if (var1 == 0) { + var1 = 32; + } + + Sounds.setMusicVolume(-var1 + Sounds.musicVolume); + } else { + Sounds.setMusicVolume(0); + } + + } + + @SuppressWarnings("SameParameterValue") + public static Sprite captureScreenRect(int x, int y, int width, int height) { + final int offsetX; + if (x < 0) { + width += x; + offsetX = -x; + x = 0; + } else { + offsetX = 0; + } + + final int offsetY; + if (y < 0) { + height += y; + offsetY = -y; + y = 0; + } else { + offsetY = 0; + } + + if (x + width > ShatteredPlansClient.SCREEN_WIDTH) { + width = ShatteredPlansClient.SCREEN_WIDTH - x; + } + if (y + height > ShatteredPlansClient.SCREEN_HEIGHT) { + height = ShatteredPlansClient.SCREEN_HEIGHT - y; + } + + if (width >= 0 && height >= 0) { + final Sprite dest = new Sprite(width, height); + + final int screenStride = Drawing.width - width; + final int destStride = dest.width - width; + int screenPos = y * Drawing.width + x - 1; + int destPos = -1; + + for (int i = 0; i < height; ++i) { + for (int j = 0; j < width; ++j) { + ++destPos; + ++screenPos; + dest.pixels[destPos] = Drawing.screenBuffer[screenPos]; + } + + screenPos += screenStride; + destPos += destStride; + } + + dest.y = offsetY; + dest.x = offsetX; + return dest; + } else { + return null; + } + } + + public static void drawShine(final int x, final int y, final int width, final int height, final int color, final boolean var0) { + if (width > 20 && height > 20) { + final int[] bounds = new int[4]; + Drawing.saveBoundsTo(bounds); + Drawing.fillRoundedRect(x, y, width, height, 10, 0, 200); + FloatingPanel.a669am(width - 10, color, height - 10, x, y); + Drawing.horizontalLine(x + 10, y, width - 20, 2052949); + Drawing.horizontalLine(10 + x, y + height, width - 20, 0); + Drawing.expandBoundsToInclude(x, y, x + 10, 10 + y); + Drawing.strokeCircle(x + 10, 10 + y, 10, 2052949); + Drawing.restoreBoundsFrom(bounds); + Drawing.expandBoundsToInclude(width - 10 + x, y, x + width, y + 10); + Drawing.strokeCircle(x + width - 11, 10 + y, 10, 2052949); + Drawing.restoreBoundsFrom(bounds); + Drawing.expandBoundsToInclude(x, y + (height - 10), 10 + x, y + height); + Drawing.strokeCircle(x + 10, height - 10 + y - 1, 10, 0); + Drawing.restoreBoundsFrom(bounds); + Drawing.expandBoundsToInclude(x + width - 10, height - 10 + y, x + width, height + y); + Drawing.strokeCircle(width + x - 10 - 1, height + y - 11, 10, 0); + Drawing.restoreBoundsFrom(bounds); + + for (int var8 = 0; var8 < height - 20; ++var8) { + final int color2 = Drawing.alphaOver(0, 0x1f5355, var8 * 256 / (height - 20)); + Drawing.setPixel(x, 10 + y + var8, color2); + Drawing.setPixel(width + (x - 1), var8 + 10 + y, color2); + } + + if (var0) { + SHINE_LEFT.drawAdd(x + 4, y + 3, 256); + final int var8 = x + 4 + SHINE_LEFT.width; + final int var9 = x + width - 3 - SHINE_RIGHT.width; + SHINE_RIGHT.drawAdd(var9, 3 + y, 64); + + for (int var11 = var8; var11 < var9; ++var11) { + final int var10 = 192 * (var9 - var11) / (-var8 + var9) + 64; + SHINE_MID.drawAdd(var11, 3 + y, var10); + } + } + } + } + + public static void drawShine(final int x, final int y, final int width, final int height, final int color) { + drawShine(x, y, width, height, color, false); + } + + private static void a669ks(int var0, final int var2, int var3, int var4) { + if (Drawing.top > var4) { + var3 += (var4 - Drawing.top) * var2; + var0 += var4 - Drawing.top; + var4 = Drawing.top; + } + + if (Drawing.bottom < var4 + var0) { + var0 = Drawing.bottom - var4; + } + + final int var5 = Drawing.width + var2; + int var7 = Drawing.width * var4 + var3; + + for (int var8 = var3; var0 > 0; var8 += var2) { + if (Drawing.left <= var8 && var8 < Drawing.right) { + var3 = Drawing.screenBuffer[var7]; + var4 = 2458760 + var3; + final int var6 = (16711935 & var3) + (2424968); + var3 = (16777472 & var6) + (var4 - var6 & 65536); + final int var01 = -(var3 >>> 8) + var3; + Drawing.screenBuffer[var7] = var01 | var4 - var3; + } + + var7 += var5; + --var0; + } + + } + + public static Sprite achievementIcon(final int index) { + Sprite sprite = ACHIEVEMENT_ICONS[index]; + if (sprite == null) { + ACHIEVEMENT_ICONS[index] = sprite = new Sprite(32, 32); + Drawing.saveContext(); + sprite.installForDrawing(); + ACHIEVEMENTS[index].g093(); + Drawing.restoreContext(); + } + return sprite; + } + + private static int breakLinesLogin(final Font font, final String text, final String[] lines) { + //noinspection SuspiciousNameCombination + final int targetWidth = ShatteredPlansClient.SCREEN_HEIGHT; + final int singleLineWidth = font.measureLineWidth(text); + if (singleLineWidth <= targetWidth && !text.contains("
")) { + lines[0] = text; + return 1; + } + + final int var6 = (targetWidth + singleLineWidth - 1) / targetWidth; + final int var100 = singleLineWidth / var6; + int i = 0; + int var7 = 0; + + for (int j = 0; j < text.length(); ++j) { + final char c = text.charAt(j); + if (c == ' ' || c == '-') { + final String var11 = text.substring(var7, 1 + j).trim(); + final int var12 = font.measureLineWidth(var11); + if (var12 >= var100) { + var7 = 1 + j; + lines[i++] = var11; + } + } + + if (c == '>' && text.regionMatches(j - 3, "
", 0, 4)) { + lines[i++] = text.substring(var7, j - 3).trim(); + var7 = 1 + j; + } + } + + if (var7 < text.length()) { + lines[i++] = text.substring(var7).trim(); + } + + return i; + } + + private static int a313ch(final int var0, final int var1) { + int var2 = 0; + + for (int var3 = _vob; _tc.length > var2; ++var2) { + final int var4 = _kbD[var2]; + if (var4 < 0) { + var3 += get_idb(); + } else { + final int var5 = a234or(_tc[var2]); + var3 += 2; + final int var6 = -(var5 >> 1) + ShatteredPlansClient.SCREEN_CENTER_X; + if (a423((8 << 1) + get_idb(), var1, var6 - 8, var3, (8 << 1) + var5, var0)) { + return var4; + } + + var3 += get_idb() + 2 + (8 << 1); + } + } + + return -1; + } + + public static void showLobbyDialog(final String text, final boolean var6, final int which) { + isLobbyDialogOpen = true; + if (which == 0) { + final int var7 = breakLinesLogin(FONT, text, BROKEN_LINES_LOGIN); + final int var8 = var7 + 3; + _tc = new String[var8]; + _kbD = new int[var8]; + + for (int var9 = 0; var9 < var8; ++var9) { + _kbD[var9] = -1; + } + + _py = new int[2]; + + if (var7 >= 0) { + System.arraycopy(BROKEN_LINES_LOGIN, 0, _tc, 0, var7); + } + + _tc[var8 - 3] = ""; + _tc[var8 - 2] = StringConstants.FS_BUTTON_MEMBERS; + _kbD[var8 - 2] = 0; + _py[0] = 1; + _tc[var8 - 1] = StringConstants.FS_BUTTON_CLOSE; + _kbD[var8 - 1] = 1; + _py[1] = 2; + } else if (which == 1) { + final int var7 = breakLinesLogin(FONT, text, BROKEN_LINES_LOGIN); + final int var8 = var7 + 2; + _tc = new String[var8]; + _kbD = new int[var8]; + + for (int var9 = 0; var9 < var8; ++var9) { + _kbD[var9] = -1; + } + + _py = new int[1]; + + if (var7 >= 0) System.arraycopy(BROKEN_LINES_LOGIN, 0, _tc, 0, var7); + + _tc[var8 - 2] = ""; + _tc[var8 - 1] = StringConstants.FS_BUTTON_CLOSE; + _kbD[var8 - 1] = 0; + _py[0] = 2; + } else { + throw new IllegalArgumentException(); + } + + _nsnb.itemCount = _py.length; + int var7 = 0; + + for (int var8 = 0; _tc.length > var8; ++var8) { + int var9 = a234or(_tc[var8]); + if (_kbD[var8] != -1) { + var9 += 2 * 8; + } + + if (var7 < var9) { + var7 = var9; + } + } + + _ahR = -(var7 >> 1) + var7 + ShatteredPlansClient.SCREEN_CENTER_X; + _ldj = -(var7 >> 1) + ShatteredPlansClient.SCREEN_CENTER_X; + _rnb = (2 + 8 << 1) * _nsnb.itemCount; + + for (int var8 = 0; var8 < _tc.length; ++var8) { + _rnb += get_idb(); + } + + _vob = ShatteredPlansClient.SCREEN_CENTER_Y - (_rnb >> 1); + _nsnb.setSelectedItem(a313ch(JagexApplet.mouseY, JagexApplet.mouseX), 0, var6); + } + + private static boolean a423(final int var0, final int var1, final int var2, final int var4, final int var5, final int var6) { + return var2 <= var1 && var2 + var5 > var1 && var6 >= var4 && var6 < var0 + var4; + } + + private static int a234or(final String var1) { + return FONT.measureLineWidth(var1); + } + + static void showFullscreenDialog(final @NotNull Menu.FullscreenDialog which, final boolean isMouseSelection) { + currentFullscreenDialog = which; + isFullscreenDialogOpen = true; + if (currentFullscreenDialog == FullscreenDialog.MEMBERS_ONLY_NOT_LOGGED_IN) { + final int var3 = breakLinesLogin(FONT, StringConstants.FS_NONMEMBER, _tsK); + final int var4 = 3 + var3; + _tuef = new String[var4]; + _ssa = new int[var4]; + + for (int i = 0; i < var4; ++i) { + _ssa[i] = -1; + } + + _E = new DialogOption[2]; + + if (var3 >= 0) System.arraycopy(_tsK, 0, _tuef, 0, var3); + + _tuef[var4 - 3] = ""; + _tuef[var4 - 2] = StringConstants.FS_BUTTON_MEMBERS; + _ssa[var4 - 2] = 0; + _E[0] = DialogOption.MEMBERS; + _tuef[var4 - 1] = StringConstants.FS_BUTTON_CLOSE; + _ssa[var4 - 1] = 1; + _E[1] = DialogOption.CLOSE; + } else if (currentFullscreenDialog == FullscreenDialog.MEMBERS_ONLY_LOGGED_IN) { + final int var3 = breakLinesLogin(FONT, StringConstants.FS_NONMEMBER, _tsK); + final int var4 = 2 + var3; + _tuef = new String[var4]; + _ssa = new int[var4]; + + for (int var5 = 0; var4 > var5; ++var5) { + _ssa[var5] = -1; + } + + _E = new DialogOption[1]; + + if (var3 >= 0) System.arraycopy(_tsK, 0, _tuef, 0, var3); + + _tuef[var4 - 2] = ""; + _tuef[var4 - 1] = StringConstants.FS_BUTTON_CLOSE; + _ssa[var4 - 1] = 0; + _E[0] = DialogOption.CLOSE; + } else if (currentFullscreenDialog == FullscreenDialog.ACCEPT_COUNTDOWN) { + final int var3 = breakLinesLogin(FONT, Strings.format(StringConstants.FS_ACCEPT_COUNTDOWN_SING, "
<%0>
"), _tsK); + final int var4 = IntStream.range(0, var3).filter(var5 -> "<%0>".equals(_tsK[var5])).findFirst().orElse(-1); + if (var4 == -1) { + throw new IllegalStateException(); + } + + _kpo = new String[var4]; + System.arraycopy(_tsK, 0, _kpo, 0, var4); + _kdb = new String[var3 - var4 - 1]; + final int len = var3 + (-var4 - 1); + System.arraycopy(_tsK, var4 + 1, _kdb, 0, len); + final int var3a = breakLinesLogin(FONT, Strings.format(StringConstants.FS_ACCEPT_COUNTDOWN_PL, "
<%0>
"), _tsK); + final int var4a = IntStream.range(0, var3a).filter(var5 -> "<%0>".equals(_tsK[var5])).findFirst().orElse(-1); + if (var4a == -1) { + throw new IllegalStateException(); + } + + _nld = new String[var4a]; + System.arraycopy(_tsK, 0, _nld, 0, var4a); + _hmp = new String[var3a - var4a - 1]; + System.arraycopy(_tsK, var4a + 1, _hmp, 0, var3a - var4a - 1); + final int var5 = Math.max(_kpo.length, _nld.length); + final int var6 = Math.max(_hmp.length, _kdb.length); + final int var7 = var6 + var5 + 7; + _tuef = new String[var7]; + _ssa = new int[var7]; + + for (int var8 = 0; var8 < var7; ++var8) { + _ssa[var8] = -1; + } + + _E = new DialogOption[2]; + _tuef[0] = StringConstants.FS_ACCEPT_BEFORE_ACCEPT; + _ssa[1] = 0; + _tuef[1] = StringConstants.FS_BUTTON_ACCEPT; + _tuef[2] = StringConstants.FS_ACCEPT_AFTER_ACCEPT; + _ssa[3] = 1; + _tuef[5] = ""; + _E[1] = DialogOption.ACCEPT; + _E[0] = DialogOption.CLOSE; + _tuef[3] = StringConstants.FS_BUTTON_CANCEL; + _tuef[4] = StringConstants.FS_ACCEPT_AFTER_CANCEL; + + for (int var8 = 0; var8 < var5; ++var8) { + _tuef[var8 + 6] = _nld.length + var8 - var5 >= 0 ? _nld[var8 - (-_nld.length + var5)] : ""; + } + + _tuef[var5 + 6] = null; + _ssa[6 + var5] = -2; + + for (int var8 = 0; var6 > var8; ++var8) { + _tuef[7 - (-var5 - var8)] = var8 >= _hmp.length ? "" : _hmp[var8]; + } + + _brp = PseudoMonotonicClock.currentTimeMillis(); + } else if (currentFullscreenDialog == FullscreenDialog.UNAVAILABLE) { + final int var3 = breakLinesLogin(FONT, StringConstants.FS_UNAVAILABLE, _tsK); + + final int var4 = 2 + var3; + _tuef = new String[var4]; + _ssa = new int[var4]; + + for (int var5 = 0; var5 < var4; ++var5) { + _ssa[var5] = -1; + } + + _E = new DialogOption[1]; + + if (var3 >= 0) System.arraycopy(_tsK, 0, _tuef, 0, var3); + + _tuef[var4 - 2] = ""; + _tuef[var4 - 1] = StringConstants.FS_BUTTON_CLOSE; + _ssa[var4 - 1] = 0; + _E[0] = DialogOption.CLOSE; + } else if (currentFullscreenDialog == FullscreenDialog.LOST_FOCUS) { + final int var3 = breakLinesLogin(FONT, StringConstants.FS_FOCUS, _tsK); + final int var4 = var3 + 2; + _tuef = new String[var4]; + _ssa = new int[var4]; + + for (int var5 = 0; var4 > var5; ++var5) { + _ssa[var5] = -1; + } + + _E = new DialogOption[1]; + + if (var3 >= 0) System.arraycopy(_tsK, 0, _tuef, 0, var3); + + _tuef[var4 - 2] = ""; + _tuef[var4 - 1] = StringConstants.FS_BUTTON_CLOSE; + _ssa[var4 - 1] = 0; + _E[0] = DialogOption.CLOSE; + } else if (currentFullscreenDialog == FullscreenDialog.TIMEOUT) { + final int var3 = breakLinesLogin(FONT, StringConstants.FS_TIMEOUT, _tsK); + final int var4 = 3 + var3; + _tuef = new String[var4]; + _ssa = new int[var4]; + + for (int var5 = 0; var4 > var5; ++var5) { + _ssa[var5] = -1; + } + + _E = new DialogOption[2]; + + if (var3 >= 0) System.arraycopy(_tsK, 0, _tuef, 0, var3); + + _tuef[var4 - 3] = ""; + _tuef[var4 - 2] = StringConstants.FS_BUTTON_TRY_AGAIN; + _ssa[var4 - 2] = 0; + _E[0] = DialogOption.TRY_AGAIN; + _tuef[var4 - 1] = StringConstants.FS_BUTTON_CLOSE; + _ssa[var4 - 1] = 1; + _E[1] = DialogOption.CLOSE; + } else { + throw new IllegalArgumentException(); + } + + _gsl.itemCount = _E.length; + int var3 = 0; + + for (final String item : _tuef) { + final int var5 = vm_.a827(item); + if (var3 < var5) { + var3 = var5; + } + } + + if (currentFullscreenDialog == FullscreenDialog.ACCEPT_COUNTDOWN) { + String var10; + for (final String value : _kpo) { + var10 = value; + final int var7 = vm_.a827(var10); + if (var7 > var3) { + var3 = var7; + } + } + + for (final String s : _kdb) { + var10 = s; + final int var7 = vm_.a827(var10); + if (var7 > var3) { + var3 = var7; + } + } + } + + _dmra = (2 + 8 << 1) * _gsl.itemCount; + _dbf = ShatteredPlansClient.SCREEN_CENTER_X - (var3 >> 1); + _hoa = -(var3 >> 1) + var3 + ShatteredPlansClient.SCREEN_CENTER_X; + + for (int var4 = 0; var4 < _tuef.length; ++var4) { + _dmra += get_idb(); + } + + _uqk = ShatteredPlansClient.SCREEN_CENTER_Y - (_dmra >> 1); + if (currentFullscreenDialog == FullscreenDialog.ACCEPT_COUNTDOWN) { + _gsl.setSelectedItem(-1, -1, isMouseSelection); + } else { + _gsl.setSelectedItem(a313gui(JagexApplet.mouseX, JagexApplet.mouseY), 0, isMouseSelection); + } + } + + public static void a540fm(final boolean isMouseSelection) { + final FullscreenDialog var2; + if (JagexApplet.membershipLevel <= 0) { + if (JagexApplet.isAnonymous) { + var2 = FullscreenDialog.MEMBERS_ONLY_NOT_LOGGED_IN; + } else { + var2 = FullscreenDialog.MEMBERS_ONLY_LOGGED_IN; + } + } else { + ShatteredPlansClient.fullScreenCanvas = createFullScreenCanvas(); + + if (ShatteredPlansClient.fullScreenCanvas == null) { + var2 = FullscreenDialog.UNAVAILABLE; + } else { + JagexApplet.attachToCanvas(ShatteredPlansClient.fullScreenCanvas); + var2 = FullscreenDialog.ACCEPT_COUNTDOWN; + } + } + + showFullscreenDialog(var2, isMouseSelection); + } + + private static FullScreenCanvas createFullScreenCanvas() { + final Frame var5 = JagexApplet.createFullScreenFrame(); + if (var5 == null) { + return null; + } else { + final FullScreenCanvas var6 = new FullScreenCanvas(); + var6.frame = var5; + var6.frame.add(var6); + var6.setBounds(0, 0, ShatteredPlansClient.SCREEN_WIDTH, ShatteredPlansClient.SCREEN_HEIGHT); + var6.addFocusListener(var6); + var6.requestFocus(); + return var6; + } + } + + static int a313gui(final int var0, final int var1) { + int var2 = 0; + + for (int var3 = _uqk; _tuef.length > var2; ++var2) { + final int var4 = _ssa[var2]; + if (var4 >= 0) { + final int var5 = vm_.a827(_tuef[var2]); + final int var6 = ShatteredPlansClient.SCREEN_CENTER_X - (var5 >> 1); + var3 += 2; + if (a423(get_idb() + (8 << 1), var0, var6 - 8, var3, (8 << 1) + var5, var1)) { + return var4; + } + + var3 += get_idb() + (8 << 1) + 2; + } else { + var3 += get_idb(); + } + } + + return -1; + } + + private static void setItems(@MagicConstant(valuesFromClass = Id.class) final int group, final int[] items) { + Menu.items[group] = items; + menus[group] = new Menu(group); + } + + public static void updateAvailableMenuItems() { + setItems(Id.RATINGS, RATINGS_MENU_ITEMS); + setItems(Id.ACHIEVEMENTS, ACHIEVEMENTS_MENU_ITEMS); + if (!JagexApplet.isAnonymous && JagexApplet.membershipLevel > 0) { + setItems(Id.PAUSE_SINGLEPLAYER, MEMBERS_PAUSE_MENU_SINGLEPLAYER_ITEMS); + setItems(Id.PAUSE_MULTIPLAYER_1, MEMBERS_PAUSE_MENU_MULTIPLAYER_ITEMS_1); + setItems(Id.PAUSE_MULTIPLAYER_2, MEMBERS_PAUSE_MENU_MULTIPLAYER_ITEMS_2); + setItems(Id.PAUSE_MULTIPLAYER_3, MEMBERS_PAUSE_MENU_MULTIPLAYER_ITEMS_3); + } + } + + static void closeLobbyDialog() { + isLobbyDialogOpen = false; + } + + static int a137ch() { + boolean var0 = false; + + while (JagexApplet.nextTypedKey()) { + _nsnb.processKeyInputVertical(); + if (_nsnb.isItemActive()) { + var0 = true; + } + } + + _nsnb.processMouseInput(a313ch(JagexApplet.mouseY, JagexApplet.mouseX), a313ch(JagexApplet.mousePressY, JagexApplet.mousePressX)); + if (_nsnb.isItemActive()) { + var0 = true; + } + + int var1 = 0; + if (var0 && _nsnb.selectedItem >= 0) { + var1 = _py[_nsnb.selectedItem]; + if (var1 == 2) { + closeLobbyDialog(); + } + } + + return var1; + } + + static void a150rg() { + final int var0 = _ahR - _ldj; + _ldj = -(var0 >> 1) + ShatteredPlansClient.SCREEN_CENTER_X; + _vob = -(_rnb >> 1) + ShatteredPlansClient.SCREEN_CENTER_Y; + _ahR = _ldj + var0; + int var1 = _vob; + + for (int var2 = 0; _tc.length > var2; ++var2) { + final int var3 = _kbD[var2]; + final int var4; + if (var3 >= 0) { + if (var3 == _nsnb.selectedItem) { + var4 = 0x2ad0d6; + } else { + var4 = 0x258488; + } + } else { + var4 = 0x258488; + } + + final String var5 = _tc[var2]; + final int var6 = a234or(var5); + final int var7 = ShatteredPlansClient.SCREEN_CENTER_X - (var6 >> 1); + if (var3 >= 0) { + var1 += 2; + final NineSliceSprite var8 = buttonSprite; + if (var8 != null) { + var8.draw((8 << 1) + get_idb(), -8 + var7, var1, var6 + (8 << 1)); + } + + var1 += 8; + } + + FONT.draw(var5, var7, var1 + FONT.capHeight, var4); + if (var3 < 0) { + var1 += get_idb(); + } else { + var1 += get_idb() + 2 + 8; + } + } + + } + + public void b093(final int var2) { + final int var3 = this.c137(); + if (var3 != 0) { + if (ClientGameSession.playSession != null || ClientGameSession.spectateSession != null) { + GameUI.fadeRect(0, 0, ShatteredPlansClient.SCREEN_WIDTH, ShatteredPlansClient.SCREEN_HEIGHT, 192 + (var2 >> 1)); + } + + final int var4 = (ShatteredPlansClient.SCREEN_WIDTH - var3) / 2; + final int var5 = this.h137(); + final int var6 = this.b410(); + + final int var8 = 20 + var3; + final int var9 = var5 - 10; + final int var10 = var6 + 10; + if (ShatteredPlansClient.renderQuality.transitionQuality == RenderQuality.Level.HIGH + || ShatteredPlansClient.renderQuality.transitionQuality == RenderQuality.Level.MEDIUM) { + GameUI.fadeRect(var4, var9, var8, var10, var2 + 128); + } else { + Drawing.fillRect(var4, var9, var8, var10, 0x0d0d14, (128 - var2) << 1); + } + + drawShine(var4, var9, var8, var10); + Drawing.saveBoundsTo(_sf); + Drawing.setBounds(var4, var9, var4 + var8, var9 + var10); + this.e093(var5, 7903); + Drawing.restoreBoundsFrom(_sf); + } + } + + private void f423() { + _cleo = this.b313(JagexApplet.mouseX, JagexApplet.mouseY); + int var2 = 0; + if (JagexApplet.mouseButtonJustClicked != MouseState.Button.NONE) { + final int var3 = this.b313(JagexApplet.mousePressX, JagexApplet.mousePressY); + if (var3 >= 0) { + this.d093(var3); + } + } + + if (JagexApplet.mouseWheelRotation != 0) { + var2 = JagexApplet.mouseWheelRotation * -20; + } + + if (JagexApplet.langId == 0) { + if (JagexApplet.mouseButtonJustClicked != MouseState.Button.NONE) { + if (_cleo == -2) { + this.a366(-1); + } else if (_cleo == -3) { + this.a366(1); + } + } + } else if (JagexApplet.mouseButtonDown != MouseState.Button.NONE) { + if (_cleo == -2) { + var2 += 10; + } else if (_cleo == -3) { + var2 -= 10; + } + } + + if (JagexApplet.mouseButtonDown != MouseState.Button.NONE && _cleo == -1) { + if (this._f) { + var2 = -this._i + JagexApplet.mouseY; + } else { + this._f = true; + } + this._i = JagexApplet.mouseY; + } else { + this._f = false; + } + + if (var2 != 0) { + _c -= var2; + _acw -= var2; + if (_c < 0) { + _c = 0; + } + + if (_acw < 0) { + _acw = 0; + } + + if (_kbA < _c) { + _c = _kbA; + } + + if (_kbA < _acw) { + _acw = _kbA; + } + } + + } + + private int b474() { + if (currentMenu != this.id && nextMenu != this.id) { + return 0; + } else if (nextMenu != currentMenu && currentMenu >= 0 && nextMenu >= 0) { + final double var2 = MathUtil.ease(_ehQ, 32); + final int var4 = (int) ((-var2 + 1.0D) * (double) (80 + _tvcr[currentMenu])); + int var5 = -(((int) (var2 * (double) (_tvcr[nextMenu] - _tvcr[currentMenu])) + _tvcr[currentMenu]) / 2) + 320; + var5 += var4; + return currentMenu != this.id ? var5 : var5 - _tvcr[currentMenu] - 80; + } else { + return (ShatteredPlansClient.SCREEN_WIDTH - this.c137()) / 2; + } + } + + private void a326(int var1, int var2) { + int var4 = _mgfb == 0 ? _acw : MathUtil.ease(_mgfb, 32, _c, _acw); + final int var5 = StringConstants.INSTRUCTIONS_TABNAMES.length; + if (var4 < 0) { + var4 = 0; + } + + if (_kbA < var4) { + var4 = _kbA; + } + + final int var6 = var1 - (-_tvcr[this.id] - 18); + var1 -= 8; + Drawing.fillRoundedRect(var1 + 20, var2 + 2, 18 + _tvcr[this.id] - 60 + _ok.width, 309, 10, 0, 92); + Drawing.f669(20 + var1, 2 + var2, _tvcr[this.id] - 60 + 18 + _ok.width, 309, 10, 2458760); + final int[] var7 = new int[4]; + Drawing.saveBoundsTo(var7); + Drawing.expandBoundsToInclude(25 + var1, 5 + var2, var6 - 20, var2 + _tvct[this.id] - 14); + int var8 = -var4; + + int var9; + for (var9 = 0; var9 < var5; ++var9) { + if (var9 > 0) { + Drawing.horizontalLine(var1 + 30, 3 + var2 + var8 - 20, -var1 + var6 - 80, Drawing.WHITE); + Drawing.horizontalLine(var1 + 30, var8 + var2 + 3 - 40, -var1 + var6 - 80, Drawing.WHITE); + SMALL_FONT.draw(StringConstants.INSTRUCTIONS_TABNAMES[var9], var1 + 50, SMALL_FONT.ascent / 2 + 3 + var2 + var8 - 30, Drawing.WHITE); + } + + if (var8 <= 294 && var8 >= -294) { + this.a258(var8 + var2 + 3, var9, var1 + 30); + } + + var8 += _cbi[var9]; + } + + Drawing.restoreBoundsFrom(var7); + if (_kbA > var4) { + ShatteredPlansClient._bga.drawAdd(var1 - (-_tvcr[this.id] + 26), _tvct[this.id] + var2 - 35, 256); + if (_cleo == -3) { + ShatteredPlansClient._bga.drawAdd(_tvcr[this.id] + var1 - 26, var2 + _tvct[this.id] - 35, 256); + } + } + + if (var4 > 0) { + _ok.drawAdd(var1 + _tvcr[this.id] - 26, 5 + var2, 256); + if (_cleo == -2) { + _ok.drawAdd(_tvcr[this.id] + (var1 - 26), var2 + 5, 256); + } + } + + var9 = -(21 * var5) + 310; + var2 += 8; + int var10 = _nct; + + int var11; + int var12; + int var13; + int var16; + int var18; + int var19; + for (var11 = 0; var5 - 1 > var11; ++var11) { + var12 = _ssH[var11]; + if (var12 > 12) { + var12 = 12; + } + + var13 = var10 == 0 ? 0 : var9 * var12 / var10; + var10 -= var12; + var9 -= var13; + var13 += 21; + + int var14; + for (var14 = 0; var14 <= 16; ++var14) { + a713ir(var13, var6 - var14, var2 + var14, 65793); + } + + a669ks(16, -1, var6, var2); + a713ir(var13, var6 - 16, 16 + var2, 2458760); + var14 = _ssH[var11] - 12; + if (var14 > 0) { + final String var15 = StringConstants.INSTRUCTIONS_TABNAMES[var11]; + var16 = SMALL_FONT.measureLineWidth(var15); + final int var17 = SMALL_FONT.descent + SMALL_FONT.ascent; + var18 = var6 - 15; + var19 = (var13 - var16 >> 1) + 8 + var2; + final Sprite var20 = new Sprite(var17, var16); + Drawing.saveContext(); + var20.installForDrawing(); + SMALL_FONT.drawVertical(var15, 1 + SMALL_FONT.ascent * 3 / 4, var16 - 1, Drawing.WHITE); + Drawing.restoreContext(); + var20.drawAdd(var18, var19, 256 * var14 / 12); + } + + var2 += var13; + } + + var11 = var9 + 16; + + for (var12 = 0; var12 <= 16; ++var12) { + a713ir(-(var12 * 2) + 32 + var11, -var12 + var6, var2 + var12, 65793); + } + + a669ks(16, -1, var6, var2); + a713ir(var11, var6 - 16, var2 + 16, 2458760); + var12 = this.id == Id.INSTRUCTIONS_2 ? 8 : 16; + a669ks(var12, 1, var6 - 16, var11 + 15 + var2); + var13 = _ssH[var5 - 1] << 2; + if (var13 != 0) { + final String var21 = StringConstants.INSTRUCTIONS_TABNAMES[var5 - 1]; + final int var22 = SMALL_FONT.measureLineWidth(var21); + var16 = SMALL_FONT.descent + SMALL_FONT.ascent; + final Sprite var23 = new Sprite(var16, var22); + Drawing.saveContext(); + var23.installForDrawing(); + SMALL_FONT.drawVertical(var21, SMALL_FONT.ascent * 3 / 4 + 1, var22 - 1, Drawing.WHITE); + Drawing.restoreContext(); + var18 = var6 - 14; + var19 = (-var22 + var11 >> 1) + 16 + var2; + var23.drawAdd(var18, var19, (int) (2.67D * (double) var13)); + } + + } + + private int d313(final int var1, final int var2, final int var3) { + if (var1 < 53) { + this.e093(93, -98); + } + + int var4 = 140; + int var5 = 52; + final int[] var6 = new int[4]; + Drawing.saveBoundsTo(var6); + Drawing.a797(); + + for (int var7 = 0; var7 < 25; ++var7) { + if (var5 <= var2 && var5 + 32 > var2 && var4 <= var3 && var3 < var4 + 32) { + return var7; + } + + var5 += 42; + if (var7 % 13 == 12) { + var4 = (int) ((double) var4 + Math.sqrt(3.0D) * 21.0D); + var5 = 73; + } + } + + return -1; + } + + private void d423() { + final int var2 = _ssH.length; + int var3 = _acw + 147; + int var4 = 0; + + while (var4 < var2) { + var3 -= _cbi[var4]; + if (var3 < 0) { + break; + } + + ++var4; + } + + _os = var4; + int var5 = _cleo; + if (var5 < 0) { + var5 = _os; + } + + _nct = 0; + + int var6; + for (var4 = 0; var4 < _ssH.length; ++var4) { + var6 = _ssH[var4]; + if (var5 == var4) { + ++var6; + if (var6 > 24) { + var6 = 24; + } else { + _ssH[var4] = var6; + } + } else { + --var6; + if (var6 < 0) { + var6 = 0; + } else { + _ssH[var4] = var6; + } + } + + if (var6 > 12) { + var6 = 12; + } + + _nct += var6; + } + + if (_mgfb != 0 && ++_mgfb == 32) { + _mgfb = 0; + _c = _acw; + } + + if (_oob == null) { + _oob = new int[5]; + _erq = new int[5]; + _fgc = new int[5]; + + for (var4 = 0; var4 < 5; ++var4) { + _erq[var4] = ShatteredPlansClient.randomIntBounded(35); + _fgc[var4] = ShatteredPlansClient.randomIntBounded(35); + } + } + + var6 = ShatteredPlansClient.currentTick % 50; + if (var6 == 0) { + for (var4 = 0; var4 < 5; ++var4) { + _erq[var4] = _fgc[var4]; + _fgc[var4] = ShatteredPlansClient.randomIntBounded(35); + } + } + + } + + private void e093(final int var1, final int var2) { + final int var3 = this.b474(); + final int var5 = this._h % (this.inputState.itemCount * 16); + if (var2 != 7903) { + StringConstants.STATUS = null; + } + + for (int var6 = 0; var6 < this.inputState.itemCount; ++var6) { + final int var7 = (this._h - var6 * 4) * 256 / (this.inputState.itemCount * 4); + if (var7 > 0) { + if (var7 < 256) { + this.a921(var6, var6 == this.inputState.selectedItem, var7); + } else { + this.a663(var6, this.inputState.selectedItem == var6); + } + } + + if (items[this.id][var6] != 29 && items[this.id][var6] != 28) { + final int var4 = this.c417(var6); + if (var6 == this.inputState.selectedItem) { + MENU_HEX.draw(25 + var3, (widths[this.id] - MENU_HEX.height) / 2 + var4); + } else { + final int var8 = this.inputState.itemCount * 6 + var6 * 4; + final int var9 = Math.abs(var5 - var8); + if (var9 < this.inputState.itemCount * 2) { + MENU_HEX.draw(var3 + 25, var4 + (widths[this.id] - MENU_HEX.height) / 2, 256); + } else if (var9 < 6 * this.inputState.itemCount) { + final int var10 = (6 * this.inputState.itemCount - var9) * 256 / (this.inputState.itemCount * 4); + MENU_HEX.draw(25 + var3, (-MENU_HEX.height + widths[this.id]) / 2 + var4, var10); + } + } + } + } + + if (this.id == Id.INSTRUCTIONS_1 || this.id == Id.INSTRUCTIONS_2) { + this.a326(this.b474(), var1); + } else if (this.id == Id.ACHIEVEMENTS) { + this.j150(); + } else if (this.id == Id.RATINGS) { + this.c423(); + } else if (this.id == Id.ERROR) { + this.e423(); + } + + } + + private void e423() { + Drawing.saveBoundsTo(_kcm); + Drawing.a797(); + final int var2 = MathUtil.ease(_onc, 32, 0, 320); + final short var3 = 200; + final int var4 = this.b474() - (var2 - this.c137() >> 1); + final int var5 = this.h137() - 48 - var3; + if (var2 > 20) { + drawShine(var4, var5, var2, var3); + } + + if (_onc == 32) { + Drawing.setBounds(var4 + 8, 8 + var5, var2 + (var4 - 8), var3 + (var5 - 8)); + FONT.drawCentered(StringConstants.TEXT_ERROR, (var2 >> 1) + var4, FONT.ascent + 10 + var5, 2805974); + SMALL_FONT.drawParagraph(ShatteredPlansClient.networkErrorMessage, 10 + var4, FONT.ascent + var5 + 10, var2 - 20, -FONT.ascent + (170), 2805974, Font.HorizontalAlignment.CENTER, Font.VerticalAlignment.MIDDLE, SMALL_FONT.ascent); + } + + Drawing.restoreBoundsFrom(_kcm); + } + + private void a921(final int var1, final boolean var2, final int var3) { + @MagicConstant(valuesFromClass = Item.class) + final int var5 = items[this.id][var1]; + final String var6 = this.lookupLabel(var5); + final int var7 = !var2 ? 2458760 : 2805974; + final int var8 = widths[this.id]; + int var9 = this.getX(); + final int var10 = this.c417(var1); + FONT.draw(var6, var9, FONT.ascent + var10, var7, var3); + if (var5 == Item.SOUND_VOLUME || var5 == Item.MUSIC_VOLUME) { + var9 += _hgt; + Drawing.d669(var9, var10 + (var8 / 2 - 1), 121, 2, var7, var3); + final int var11 = var5 != Item.SOUND_VOLUME ? Sounds.musicVolume * 120 / 256 : Sounds.soundVolume * 120 / 256; + Drawing.d669(var9 + var11 - 1, 3 + var10, 3, var8 - 6, var7, var3); + } + + if (var1 == this._g) { + this.a527(var1); + } + } + + @SuppressWarnings("SameParameterValue") + private static void drawLabeledHorizontalBracket(final String label, + final int labelX, + final int labelY, + final int labelWidth, + final int bracketX1, + final int bracketX2, + final int bracketTipsY, + final int bracketHeight, + final int color) { + final int bracketSpineY = bracketTipsY + bracketHeight; + if (bracketX2 > bracketX1) { + Drawing.horizontalLine(bracketX1, bracketSpineY, 1 - bracketX1 + bracketX2, color); + } else { + Drawing.horizontalLine(bracketX2, bracketSpineY, 1 - bracketX2 + bracketX1, color); + } + + final int bracketTailX = (bracketX1 + bracketX2) / 2; + if (bracketTailX < labelX) { + Drawing.horizontalLine(bracketTailX, labelY, labelX - bracketTailX, color); + } else { + Drawing.horizontalLine(labelX, labelY, bracketTailX - labelX, color); + } + + if (bracketHeight > 0) { + Drawing.verticalLine(bracketX1, bracketTipsY, bracketHeight, color); + Drawing.verticalLine(bracketX2, bracketTipsY, bracketHeight, color); + } else { + Drawing.verticalLine(bracketX1, bracketSpineY, -bracketHeight, color); + Drawing.verticalLine(bracketX2, bracketSpineY, -bracketHeight, color); + } + + if (labelY <= bracketSpineY) { + Drawing.verticalLine(bracketTailX, labelY, bracketSpineY - labelY, color); + } else { + Drawing.verticalLine(bracketTailX, bracketSpineY, labelY - bracketSpineY, color); + } + + final int lineCount = GameUI.breakLines(label, SMALL_FONT, new int[]{labelWidth}); + SMALL_FONT.drawParagraph( + label, + labelX + 5, + labelY - ((SMALL_FONT.ascent * lineCount) / 2), + labelWidth, + lineCount * SMALL_FONT.ascent + SMALL_FONT.descent, + color, + Font.HorizontalAlignment.LEFT, + Font.VerticalAlignment.TOP, + SMALL_FONT.ascent); + } + + private void a837(final String var1, int var2, final byte var3, final int var4, final int var5, int var6, final int var7, final int var8, final int var9, int var10) { + final int var11 = var2 - (-var10 - var6); + if (var11 != 0) { + var6 = (200 * var6 + var11) / (2 * var11); + var2 = (var2 * 200 + var11) / (var11 * 2); + var10 = (200 * var10 + var11) / (var11 * 2); + } + + String var12; + if (var8 != -1) { + var12 = 1 + var8 + "."; + SMALL_FONT.drawRightAligned(var12, 15 + _vnr[0] + var5, var7, var9); + } + + SMALL_FONT.draw(var1, var5 - (-_vnr[0] - 20), var7, var9); + var12 = Integer.toString(var4); + SMALL_FONT.drawCentered(var12, var5 + _vnr[1], var7, var9); + var12 = var11 >= 50 ? "50+" : Integer.toString(var11); + SMALL_FONT.drawCentered(var12, _vnr[2] + var5, var7, var9); + var12 = var2 + "%"; + if (var3 >= -116) { + this.a827(-46, 11, -112, -101, -46, -96); + } + + SMALL_FONT.drawCentered(var12, var5 + _vnr[3], var7, var9); + var12 = var10 + "%"; + SMALL_FONT.drawCentered(var12, var5 + _vnr[4], var7, var9); + var12 = var6 + "%"; + SMALL_FONT.drawCentered(var12, _vnr[5] + var5, var7, var9); + } + + public void c326(final int var1, final int var3) { + if (ClientGameSession.playSession != null || ClientGameSession.spectateSession != null) { + a587oa(); + } + + final int var4 = this.c137(); + final int var5 = this.h137(); + final int var6 = this.b410(); + final double var7 = MathUtil.ease(var3, 128); + final int var9 = (ShatteredPlansClient.SCREEN_WIDTH - var4) / 2; + final int var10 = (int) ((double) (_tvcr[this.id] + 80) * (1.0D - var7)); + final int var12 = 20 + var4; + final int var13 = var5 - 10; + final int var14 = var6 + 10; + drawShine(var9, var13, var12, var14); + Drawing.saveBoundsTo(_sf); + final int var15 = var10 + (var9 - 20); + final int var16 = var12 + var9; + Drawing.setBounds(var9, var13, Math.min(var15, var16), var14 + var13); + this.e093(var5, 7903); + Drawing.setBounds(var9, var13, var9 + var12, var14 + var13); + menus[var1].e093(var5, 7903); + Drawing.restoreBoundsFrom(_sf); + } + + private void c423() { + Drawing.saveBoundsTo(_kcm); + Drawing.a797(); + + if (JagexApplet.isAnonymous) { + this.d150(); + } else { + if (_riI == null) { + _riI = a250jba(); + } + + final int var2 = MathUtil.ease(_nba, 32, 0, 560); + final short var3 = 200; + final int var4 = this.b474() - (-this.c137() + var2 >> 1); + final int var5 = this.h137() - var3 - 24; + if (var2 > 20) { + drawShine(var4, var5, var2, var3); + } + + Drawing.setBounds(var4 + 8, 8 + var5, var2 + (var4 - 8), var3 + var5 - 8); + int var6 = 2805974; + int var7 = 16 + var5 + SMALL_FONT.ascent; + SMALL_FONT.drawCentered(StringConstants.RATING_RATING, _vnr[1] + var4, var7, var6); + SMALL_FONT.drawCentered(StringConstants.RATING_PLAYED, _vnr[2] + var4, var7, var6); + SMALL_FONT.drawCentered(StringConstants.RATING_WON, var4 + _vnr[3], var7, var6); + SMALL_FONT.drawCentered(StringConstants.RATING_LOST, _vnr[4] + var4, var7, var6); + SMALL_FONT.drawCentered(StringConstants.RATING_DRAWN, _vnr[5] + var4, var7, var6); + var7 += 24; + String var8; + if (_riI._q) { + if (_riI._n == null) { + var8 = StringConstants.SERVICE_UNAVAILABLE; + } else { + var8 = StringConstants.RATING_NO_RATINGS; + final String[] var9 = _riI._n[_ffy]; + final int[] var10 = _riI._m[_ffy]; + boolean var11 = false; + + for (int var12 = 0; var12 < 10; ++var12) { + if (var9[var12] != null) { + var6 = 2805974; + final String var13 = var9[var12]; + if (JagexApplet.a623jp(var13)) { + var11 = true; + var6 = Drawing.WHITE; + } + + this.a837(var13, var10[1 + var12 * 4], (byte) -128, var10[4 * var12], var4, var10[2 + 4 * var12], var7, var12, var6, var10[3 + 4 * var12]); + var8 = ""; + } + + var7 += 15; + } + + if (!var11 && _riI._h + _riI._i + _riI._r > 0) { + this.a837(JagexApplet.playerDisplayName, _riI._i, (byte) -120, _riI._l, var4, _riI._r, var7, -1, var6, _riI._h); + } + } + } else { + var8 = StringConstants.PLEASE_WAIT; + } + + final int i = (SMALL_FONT.ascent + var3 >> 1) + var5; + SMALL_FONT.drawCentered(var8, var4 + (var2 >> 1), i, 2805974); + Drawing.restoreBoundsFrom(_kcm); + } + } + + private void d150() { + final short var2 = 420; + + final int var3 = MathUtil.ease(_nba, 32, 0, var2); + final byte var4 = 80; + final int var5 = this.b474() - (var3 - this.c137() >> 1); + final int var6 = this.h137() - 60 - var4 - 48; + if (var3 > 20) { + drawShine(var5, var6, var3, var4); + } + + Drawing.setBounds(8 + var5, 8 + var6, var5 + var3 - 8, var6 - 8 + var4); + SMALL_FONT.drawCentered(StringConstants.CREATE_TO_USE, 320, (SMALL_FONT.ascent + var4 >> 1) + var6, Drawing.WHITE); + Drawing.restoreBoundsFrom(_kcm); + } + + public void a126(final boolean var3) { + int var1 = 0; + if (this.inputState.selectedItem != -1) { + var1 = this.inputState.selectedItem; + } + + if (this.id == Id.ACHIEVEMENTS && areAchievementsOffline && ShatteredPlansClient.achievementRequest == null) { + ShatteredPlansClient.achievementRequest = JagexApplet.createAchievementRequest(); + } + + this.inputState.setSelectedItem(this.getHoveredItemIndex(JagexApplet.mouseX, JagexApplet.mouseY), var1, var3); + this._h = 0; + _anc = -1; + + _sbe = -1; + this._g = -1; + _tvcq = ShatteredPlansClient.currentTick; + + for (int i = 1; i < 6; ++i) { + _ssH[i] = 0; + } + + _os = 0; + if (this.id == Id.ACHIEVEMENTS) { + _upd = 0; + } + + _cleo = -1; + _nct = 24; + _ssH[0] = 24; + if (_cbi == null && (this.id == Id.INSTRUCTIONS_1 || this.id == Id.INSTRUCTIONS_2)) { + c487hd(); + } + } + + private void a663(final int var1, final boolean var3) { + @MagicConstant(valuesFromClass = Item.class) + final int var4 = items[this.id][var1]; + final String var5 = this.lookupLabel(var4); + final int var6 = var3 ? 2805974 : 2458760; + final int var7 = widths[this.id]; + int var8 = this.getX(); + final int var9 = this.c417(var1); + if (var4 == Item.SOUND_VOLUME || var4 == Item.MUSIC_VOLUME) { + FONT.draw(var5, var8, var9 + FONT.ascent, var6); + var8 += _hgt; + Drawing.strokeRectangle(var8, var9 + var7 / 2 - 1, 121, 2, var6); + final int var10 = var4 != Item.SOUND_VOLUME ? 120 * Sounds.musicVolume / 256 : Sounds.soundVolume * 120 / 256; + Drawing.strokeRectangle(var10 + (var8 - 1), 3 + var9, 3, var7 - 6, var6); + } else { + FONT.draw(var5, var8, FONT.ascent + var9, var6); + } + + if (var1 == this._g) { + this.a527(var1); + } + + } + + private void a487() { + if (++_leb > 32) { + _leb = 32; + } + + int var2; + for (var2 = 0; ACHIEVEMENTS.length > var2; ++var2) { + if (var2 != _sbe && _anc != var2) { + _gvsb[var2] = null; + } + } + + if (_ekA != 0 && ++_ekA >= 32) { + _upd = _qBb; + _ekA = 0; + } + + var2 = _anc != -1 ? _anc : _sbe; + int var3 = var2 != -1 ? 32 + 16 * _ndd[var2] : 0; + if (var2 == 24) { + final boolean var4 = (0x1000000 & unlockedAchievementsBitmap) != 0; + var3 = var4 ? 32 + 16 * _ndd[24] : 0; + } + + if (_qBb != var3) { + if (_ekA != 0) { + _upd = MathUtil.ease(_ekA, 32, _upd, _qBb); + } + + _ekA = 1; + _qBb = var3; + } + + } + + private int a417(final int index) { + @MagicConstant(valuesFromClass = Item.class) + final int item = items[this.id][index]; + return item == Item.SOUND_VOLUME || item == Item.MUSIC_VOLUME + ? _hgt + 120 + : FONT.measureLineWidth(this.lookupLabel(item)); + } + + private void a258(int y, final int var3, int x) { + final int var6 = _tvcr[this.id] - 60; + final int var7 = _tvct[this.id] - 50; + final int var8 = 1 + SMALL_FONT.ascent * 3 / 4; + String var5; + if (var3 == 0) { + var5 = StringConstants.TEXT_INSTRUCTIONS_0; + } else if (var3 == 1) { + var5 = StringConstants.TEXT_INSTRUCTIONS_GLOSSARY_1; + } else if (var3 == 2) { + var5 = StringConstants.TEXT_INSTRUCTIONS_GLOSSARY_2; + } else { + if (var3 == 3) { + if (JagexApplet.langId == 1) { + x -= 5; + } + + INSTR_MAIN_VIEW.c093(x + 5, y + 5); + final int labelsX = x + 345; + final int labelsWidth = 120; + drawLabeledHorizontalBracket(StringConstants.TEXT_INSTRUCTIONS_MV_TIME, labelsX, 8 + y, labelsWidth, x + 315 + 5, x + 5 + 315, y + 8, 0, RED); + drawLabeledVerticalBracket(StringConstants.TEXT_INSTRUCTIONS_MV_READY, labelsX, 25 + y, labelsWidth, 315 + x + 5, 25 + y, y + 25, 5, RED); + drawLabeledVerticalBracket(StringConstants.TEXT_INSTRUCTIONS_MV_WORMHOLE, labelsX, 69 + y, labelsWidth, x + 205, 78 + 5 + y, 78 + y + 5, 0, RED); + drawLabeledVerticalBracket(StringConstants.TEXT_INSTRUCTIONS_MV_ORDER, labelsX, 5 + y + 110, labelsWidth, 5 + x + 195, 95 + 5 + y, y + 115, 0, RED); + drawLabeledVerticalBracket(StringConstants.TEXT_INSTRUCTIONS_MV_FRAME, labelsX, y + 5 + 160, labelsWidth, 5 + x + 86, y + 5 + 120, 5 + y + 200, 5, RED); + return; + } + + final int var13; + if (var3 == 4) { + if (JagexApplet.langId == 1) { + x -= 5; + } + + INSTR_STAR_FRAME.c093(x + 5, y + 5); + final int labelsX = x + 295; + final short labelsWidth = 220; + drawLabeledVerticalBracket(StringConstants.TEXT_INSTRUCTIONS_SF_OUTGOING, labelsX, y + 5 + 14, labelsWidth, 250 + x, y + 5, 32 + y + 5, 5, RED); + drawLabeledHorizontalBracket(StringConstants.TEXT_INSTRUCTIONS_SF_GARRISON, labelsX, 40 + y + 5, labelsWidth, 5 + x + 139, 139 + 5 + x, y + 85, -5, RED); + drawLabeledVerticalBracket(StringConstants.TEXT_INSTRUCTIONS_SF_NAME, labelsX, 70 + y + 5, labelsWidth, 188 + 5 + x, 5 + y + 130, 100 + 5 + y, 5, RED); + drawLabeledVerticalBracket(StringConstants.TEXT_INSTRUCTIONS_SF_RESOURCES, labelsX, 95 + y, labelsWidth, x + 235, y + 130, 5 + y + 260, 10, RED); + drawLabeledVerticalBracket(StringConstants.TEXT_INSTRUCTIONS_SF_INCOMING, labelsX, 5 + y + 110, labelsWidth, 210 + 5 + x, 264 + y + 5, 5 + y + 294, 25, RED); + y += 150; + short var34 = 400; + if (JagexApplet.langId == 1) { + var34 = 390; + } + + a487ai(); + Drawing.drawCircleGradientAdd(16 * var34 + _emc[0], _pmDb[0] + y * 16, 50, 7, GameUI._hs); + SMALL_FONT.draw(StringConstants.TEXT_INSTRUCTIONS_ICON_TERRAFORMED, var34 + 22, y + SMALL_FONT.ascent / 4, Drawing.WHITE); + y += 40; + Drawing.drawCircleGradientAdd(16 * var34 + _emc[0], _pmDb[0] + 16 * y, 50, 7, GameUI._hs); + Drawing.drawCircleGradientAdd(_emc[1] + 16 * var34, 16 * y + _pmDb[1], 50, 7, GameUI._hs); + SMALL_FONT.draw(StringConstants.TEXT_INSTRUCTIONS_ICON_NEUTRAL, var34 + 22, SMALL_FONT.ascent / 4 + y, Drawing.WHITE); + y += 40; + Drawing.drawCircleGradientAdd(16 * var34 + _emc[0], y * 16 + _pmDb[0], 50, 7, GameUI._hs); + Drawing.drawCircleGradientAdd(_emc[2] + var34 * 16, _pmDb[2] + 16 * y, 50, 7, GameUI._hs); + Drawing.drawCircleGradientAdd(_emc[3] + var34 * 16, _pmDb[3] + y * 16, 50, 7, GameUI._hs); + SMALL_FONT.draw(StringConstants.TEXT_INSTRUCTIONS_ICON_HOMEWORLD, var34 + 22, y + SMALL_FONT.ascent / 4, Drawing.WHITE); + y += 40; + GameView.DEFNET_ANIM_SMALL[0].b115(var34 - 15, y - 15, 30, 30); + var13 = ShatteredPlansClient.currentTick % 104; + if (var13 > 4 && var13 <= 48) { + GameView.DEFNET_ANIM_SMALL[var13 / 4].c050(var34 - 15, y - 15, 30, 30, 128); + } else { + GameView.DEFNET_ANIM_SMALL[12].c050(var34 - 15, y - 15, 30, 30, 128); + } + + SMALL_FONT.draw(StringConstants.PROJECT_NAMES[0], var34 + 22, y + SMALL_FONT.ascent / 4, Drawing.WHITE); + return; + } + + int var10; + if (var3 == 5) { + final Sprite var32 = new Sprite(80, 80); + Drawing.saveContext(); + var32.installForDrawing(); + GameView.HAMMER.a115(ShatteredPlansClient.currentTick % 25 * 200); + Drawing.restoreContext(); + var32.d093(x + 15, 8 + y); + var5 = StringConstants.TEXT_INSTRUCTIONS_PLACEMENT; + var10 = SMALL_FONT.drawParagraph(ShatteredPlansClient.templateDictionary.expand(var5), x + 80, y, var6 - 80, var7, Drawing.WHITE, Font.HorizontalAlignment.JUSTIFY, Font.VerticalAlignment.TOP, var8); + y += (3 + var10 * 4) * var8 >> 2; + final int var11 = ShatteredPlansClient.currentTick % 200; + GameView.a070eo(false, 68 + y, y + 40, var11, 55 + x, x); + this.a346(y + 40, var11, x + 55, false, x, y + 68, 0, false); + var5 = StringConstants.TEXT_INSTRUCTIONS_MOVEMENT; + var10 = SMALL_FONT.drawParagraph(ShatteredPlansClient.templateDictionary.expand(var5), x + 80, y, var6 - 80, var7, Drawing.WHITE, Font.HorizontalAlignment.JUSTIFY, Font.VerticalAlignment.TOP, var8); + y += (4 * var10 + 3) * var8 >> 2; + _kjf[ShatteredPlansClient.currentTick % _kjf.length].draw(5 + x, 42 + y); + var5 = StringConstants.TEXT_INSTRUCTIONS_PROJECTS; + SMALL_FONT.drawParagraph(ShatteredPlansClient.templateDictionary.expand(var5), 80 + x, y, var6 - 80, var7, Drawing.WHITE, Font.HorizontalAlignment.JUSTIFY, Font.VerticalAlignment.TOP, var8); + return; + } + + final int var12; + int var19; + int var20; + int var21; + int var22; + int var23; + int var24; + int var25; + if (var3 == 6) { + final ArgbSprite var30 = (ArgbSprite) GameView.ARROW_SHIP; + final ArgbSprite var33 = var30.copy(); + var33.f797(); + final int var11 = ShatteredPlansClient.currentTick % 200; + var12 = x + 35; + var13 = y + 40; + int var37; + int var38; + if (var11 < 170) { + Drawing.strokeCircle(var12, var13, 30, Drawing.WHITE); + Drawing.fillCircle(var12, var13, 30, Drawing.WHITE, 92); + GameView.a194ie(var33, var33.width << 3, var33.height << 3, var12 * 16, var13 * 16, 0, 4096); + Drawing.fillCircle(var12, var13, 9, 0, 92); + GameView.FLEET_BUTTONS[0].draw(-(GameView.FLEET_BUTTONS[0].width / 2) + 30 + var12, var13 - GameView.FLEET_BUTTONS[0].height / 2); + GameView.FLEET_BUTTONS[1].draw(var12 - 30 - GameView.FLEET_BUTTONS[0].width / 2, var13 - GameView.FLEET_BUTTONS[0].height / 2); + GameView.FLEET_BUTTONS[2].draw(var12 - GameView.FLEET_BUTTONS[0].width / 2, 30 + (var13 - GameView.FLEET_BUTTONS[0].height / 2)); + final byte var36 = 4; + if (var11 < 120) { + var38 = (var11 - 80) / 20; + if (var38 < 0) { + var38 = -var38; + } + + if (var11 >= 80) { + ++var38; + } + + var37 = var36 - var38; + if (var37 == 0) { + var37 = 1; + } + } else { + var37 = 1; + } + + SMALL_FONT.drawCentered(Integer.toString(var37), var12, 4 + var13, Drawing.WHITE); + if (var11 / 20 > 0 && var11 / 20 < 4 && var11 % 20 < 3) { + Drawing.strokeCircle(var12 + 30, var13, GameView.FLEET_BUTTONS[0].width / 2, Drawing.WHITE); + } + + if (var11 / 20 > 3 && var11 / 20 < 7 && var11 % 20 < 3) { + Drawing.strokeCircle(var12 - 30, var13, GameView.FLEET_BUTTONS[1].width / 2, Drawing.WHITE); + } + + if (var11 > 160 && var11 < 165) { + Drawing.strokeCircle(var12, 30 + var13, GameView.FLEET_BUTTONS[2].width / 2, Drawing.WHITE); + } + } + + var5 = StringConstants.TEXT_INSTRUCTIONS_FLEETSIZE; + var37 = SMALL_FONT.drawParagraph(ShatteredPlansClient.templateDictionary.expand(var5), 80 + x, y, var6 - 80, var7, Drawing.WHITE, Font.HorizontalAlignment.JUSTIFY, Font.VerticalAlignment.TOP, var8); + y += var8 * (3 + 4 * var37) >> 2; + var38 = ShatteredPlansClient.currentTick % 50; + if (var38 < 25) { + var38 = 0; + } else { + var38 -= 25; + var38 = var38 * (614400 - 16384 * var38) * var38 / 15625; + } + + int var39; + int var40; + int var41; + for (var39 = 0; var39 < 6; ++var39) { + var40 = ((var39 * 8192) - var38) / 6; + var41 = (20 * mq_.a353je(var40) >> 12) + (x + 35 << 4); + var19 = (20 * mq_.b080mq(var40) >> 12) + (40 + y << 4); + Drawing.drawCircleGradientAdd(var41, var19, 64, 255, Drawing.SHADES_OF_GRAY); + } + + for (var39 = 0; var39 < 10; ++var39) { + Drawing.horizontalLine(-(var39 >> 1) + x + 36, var39 + y + 30, -2 & var39, Drawing.WHITE); + } + + var5 = StringConstants.TEXT_INSTRUCTIONS_END_TURN; + var37 = SMALL_FONT.drawParagraph(ShatteredPlansClient.templateDictionary.expand(var5), x + 80, y, var6 - 80, var7, Drawing.WHITE, Font.HorizontalAlignment.JUSTIFY, Font.VerticalAlignment.TOP, var8); + y += var8 * (3 + var37 * 4) >> 2; + var39 = ShatteredPlansClient.currentTick / 100 % 3; + var40 = ShatteredPlansClient.currentTick % 100; + var41 = 0; + if (var40 > 20 && var40 < 40) { + var41 = var40 <= 30 ? 25 * var40 - 500 : 1000 - var40 * 25; + } + + var40 = var40 < 21 ? 12 * var40 : (var40 > 80 ? 12 * (100 - var40) : 256); + if (var39 == 0) { + var33.drawAdd(15 + x, y + 15, var40); + var33.drawAdd(15 + x, y + 15, var41); + } else { + final Sprite var42; + if (var39 == 1) { + var42 = new Sprite(var33.width + 20, var33.height); + Drawing.saveContext(); + var42.installForDrawing(); + var20 = 0; + + for (var21 = 0; var21 < 5; ++var21) { + var33.draw(var20, 0); + var20 += 5; + } + + Drawing.restoreContext(); + var42.drawAdd(x + 7, y + 15, var40); + var42.drawAdd(x + 7, 15 + y, var41); + } else if (var39 == 2) { + var42 = new Sprite(var33.width + 30, var33.height); + Drawing.saveContext(); + var42.installForDrawing(); + var20 = 0; + + for (var21 = 0; var21 < 10; var20 += 5) { + GameView.a194ie(var33, 8 * var33.width, var33.height * 8, (var20 + var33.width / 4) * 16, 4 * var33.height, 0, 2048); + GameView.a194ie(var33, 8 * var33.width, var33.height * 8, 16 * (var20 + var33.width / 4), var33.height * 12, 0, 2048); + ++var21; + } + + Drawing.restoreContext(); + var42.drawAdd(x + 3, 15 + y, var40); + var42.drawAdd(x + 3, y + 15, var41); + } + } + + var5 = StringConstants.TEXT_INSTRUCTIONS_HOTKEYS; + var37 = SMALL_FONT.drawParagraph(ShatteredPlansClient.templateDictionary.expand(var5), 80 + x, y, var6 - 80, var7, Drawing.WHITE, Font.HorizontalAlignment.JUSTIFY, Font.VerticalAlignment.TOP, var8); + y += var8 * (3 + var37 * 4) >> 2; + if (_oob != null) { + var19 = ShatteredPlansClient.currentTick % 50; + + for (var20 = 0; var20 < 5; ++var20) { + _oob[var20] = MathUtil.ease(var19, 50, _erq[var20], _fgc[var20]); + } + + var20 = x + 10; + var21 = _oob[0] + 10 + y; + + for (var22 = 1; var22 < 5; ++var22) { + for (var23 = 0; var23 < 10; ++var23) { + var24 = var22 * 10 + x + var23; + var25 = 10 + y + MathUtil.ease(var23, 10, _oob[var22 - 1], _oob[var22]); + Drawing.line(var20, var21, var24, var25, 12632256); + var21 = var25; + var20 = var24; + } + } + } + + Drawing.verticalLine(9 + x, y + 10, 35, Drawing.WHITE); + Drawing.horizontalLine(x + 10, y + 44, 40, Drawing.WHITE); + var5 = StringConstants.TEXT_INSTRUCTIONS_STATS; + SMALL_FONT.drawParagraph(ShatteredPlansClient.templateDictionary.expand(var5), x + 80, y, var6 - 80, var7, Drawing.WHITE, Font.HorizontalAlignment.JUSTIFY, Font.VerticalAlignment.TOP, var8); + return; + } + + if (var3 == 7) { + final int var9 = ShatteredPlansClient.currentTick % 200; + var10 = SMALL_FONT.drawParagraph(ShatteredPlansClient.templateDictionary.expand(StringConstants.TEXT_INSTRUCTIONS_ANIMATION), x, y, var6, var7, Drawing.WHITE, Font.HorizontalAlignment.JUSTIFY, Font.VerticalAlignment.TOP, var8); + y += (2 * var10 + 3) * var8 >> 1; + var12 = x + 125; + var13 = x + 325; + final short var14 = 150; + final byte var15 = 125; + final String[] var16 = new String[16]; + final String var17 = ShatteredPlansClient.templateDictionary.expand(StringConstants.TEXT_INSTRUCTIONS_ANIMATION_FLEETMOVE); + final String var18 = ShatteredPlansClient.templateDictionary.expand(StringConstants.TEXT_INSTRUCTIONS_ANIMATION_PROJECT); + SMALL_FONT.breakLines(var17, new int[]{var14}, var16); + SMALL_FONT.breakLines(var18, new int[]{var15}, var16); + final byte var31 = 3; + var21 = var8 + var8 * var31; + SMALL_FONT.drawParagraph(var17, var12, y, var14, var21, Drawing.WHITE, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.MIDDLE, var8); + SMALL_FONT.drawParagraph(var18, var13, y, var15, var21, Drawing.WHITE, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.MIDDLE, var8); + GameView.a070eo(false, y + 25, 25 + y, var9, x + 100, x); + this.a346(y + 25, var9, x + 100, false, x, 25 + y, 8, true); + var22 = (50 + ShatteredPlansClient.currentTick) % 800 / 200; + this.a132(x + 295, 16, var22, (var21 >> 1) + y, (ShatteredPlansClient.currentTick + 50) % 200); + int var11 = y + SMALL_FONT.ascent + var21; + final String s = ShatteredPlansClient.templateDictionary.expand(StringConstants.TEXT_INSTRUCTIONS_ANIMATION_DAMAGED); + final String a456 = ShatteredPlansClient.templateDictionary.expand(StringConstants.TEXT_INSTRUCTIONS_ANIMATION_CAPTURED); + var19 = SMALL_FONT.breakLines(s, new int[]{var14}, var16); + var20 = SMALL_FONT.breakLines(a456, new int[]{var15}, var16); + var10 = Math.max(var20, var19); + var21 = var8 * var10 + var8; + SMALL_FONT.drawParagraph(s, var12, var11, var14, var21, Drawing.WHITE, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.MIDDLE, var8); + SMALL_FONT.drawParagraph(a456, var13, var11, var15, var21, Drawing.WHITE, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.MIDDLE, var8); + GameView.a070eo(false, 90 + y, 90 + y, var9, x + 10, x + 110); + this.a346(90 + y, var9, x + 10, true, 110 + x, 90 + y, 4, true); + this.a132(x + 295, 16, -1, var11 + (var21 >> 1), (100 + ShatteredPlansClient.currentTick) % 200); + var11 += var8 + var21; + final String s1 = ShatteredPlansClient.templateDictionary.expand(StringConstants.TEXT_INSTRUCTIONS_ANIMATION_COMBAT); + var10 = SMALL_FONT.breakLines(s1, new int[]{200}, var16); + var21 = var10 * var8 + var8; + if (var21 < 40) { + var21 = 40; + } + + SMALL_FONT.drawParagraph(s1, var12, var11, 200, var21, Drawing.WHITE, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.MIDDLE, var8); + var23 = -(var9 / 24) + 15; + var24 = -(var9 / 17) + 10; + if (var24 < 0) { + var24 = 0; + } + + var25 = 4 - var9 / 30; + if (var25 < 0) { + var25 = 0; + } + + final byte var26 = 80; + int var28 = x + 18; + var11 += 10; + if (JagexApplet.langId == 0) { + var11 += 20; + } + + if (var9 >= 0 && var9 < 180) { + final int var29 = 31; + this.a827(var28, var26, var25, var29, 8421504, var11); + var28 += 30; + final int i = 90; + this.a827(var28, var26, var23, i, GameUI.PLAYER_COLORS_1[0], var11); + var28 += 30; + final int i1 = 63; + this.a827(var28, var26, var24, i1, GameUI.PLAYER_COLORS_1[2], var11); + } + + return; + } + + if (var3 == 8) { + var5 = StringConstants.TEXT_INSTRUCTIONS_PROJECT_METAL; + final int var9 = SMALL_FONT.drawParagraph(ShatteredPlansClient.templateDictionary.expand(var5), x + 40, y, var6 - 40, var7, Drawing.WHITE, Font.HorizontalAlignment.JUSTIFY, Font.VerticalAlignment.TOP, var8); + this.a132(x + 15, 20, 0, y + (SMALL_FONT.ascent * (var9 * 2 + 1) >> 2), ShatteredPlansClient.currentTick % 200); + y += (3 + var9 * 4) * var8 >> 2; + var5 = StringConstants.TEXT_INSTRUCTIONS_PROJECT_BIOMASS; + final int var9a = SMALL_FONT.drawParagraph(ShatteredPlansClient.templateDictionary.expand(var5), x + 40, y, var6 - 40, var7, Drawing.WHITE, Font.HorizontalAlignment.JUSTIFY, Font.VerticalAlignment.TOP, var8); + this.a132(15 + x, 20, 1, y + (SMALL_FONT.ascent * (1 + var9a * 2) >> 2), (ShatteredPlansClient.currentTick + 185) % 200); + y += var8 * (3 + 4 * var9a) >> 2; + var5 = StringConstants.TEXT_INSTRUCTIONS_PROJECT_ENERGY; + final int var9b = SMALL_FONT.drawParagraph(ShatteredPlansClient.templateDictionary.expand(var5), x + 40, y, var6 - 40, var7, Drawing.WHITE, Font.HorizontalAlignment.JUSTIFY, Font.VerticalAlignment.TOP, var8); + this.a132(15 + x, 20, 2, (SMALL_FONT.ascent * (2 * var9b + 1) >> 2) + y, (170 + ShatteredPlansClient.currentTick) % 200); + var5 = StringConstants.TEXT_INSTRUCTIONS_PROJECT_EXOTICS; + y += var8 * (4 * var9b + 3) >> 2; + final int var9c = SMALL_FONT.drawParagraph(ShatteredPlansClient.templateDictionary.expand(var5), 40 + x, y, var6 - 40, var7, Drawing.WHITE, Font.HorizontalAlignment.JUSTIFY, Font.VerticalAlignment.TOP, var8); + this.a132(x + 15, 20, 3, ((var9c * 2 + 1) * SMALL_FONT.ascent >> 2) + y, (155 + ShatteredPlansClient.currentTick) % 200); + return; + } + + if (var3 == 9) { + var5 = StringConstants.TEXT_INSTRUCTIONS_GAME_TYPE; + } else { + if (var3 != 10) { + throw new RuntimeException(); + } + + var5 = StringConstants.TEXT_INSTRUCTIONS_CLASSIC + StringConstants.TEXT_INSTRUCTIONS_CLASSIC_STELLAR_BOMB; + } + } + + this.a316(var8, y, x, var6, SMALL_FONT, ShatteredPlansClient.templateDictionary.expand(var5)); + } + + private int a527(final int index) { + return this.getX() + this.a417(index); + } + + private int getWidth() { + return widths[this.id]; + } + + private void a132(final int var1, int var2, final int var3, final int var4, final int var6) { + if (var6 < 150) { + int var7 = var6; + if (var6 > 125) { + var7 = -var6 + 150; + } + + int var8 = 0; + if (var7 < 25) { + if (var6 <= 125) { + var8 = MathUtil.ease(var6, 25, var2, 0); + } else { + var8 = MathUtil.ease(var6 - 125, 25, 0, -var2); + } + + var2 = MathUtil.ease(var7, 25, var2 / 2, var2); + } + + if (var3 == -1) { + GameView.HAMMER.a050(var8 + var4, 8192 * var2 / GameView.HAMMER.width, var1, 200 * (ShatteredPlansClient.currentTick % 25)); + } else { + GameView.SYSTEM_ICONS[var3].b115(-var2 + var1, var8 + var4 - var2, 2 * var2, 2 * var2); + } + + } + } + + public void prepareToSwitchAwayFrom() { + if (this.id == Id.RATINGS) { + _riI = null; + } + } + + private int b313(int var2, final int var3) { + final int var4 = 20 + this.b474() + _tvcr[this.id]; + int var5 = 10 + this.h137(); + final int var6 = _ssH.length; + if (var2 <= var4) { + if (var4 - 16 <= var2) { + var2 = var4 - var2; + int var7 = -(var6 * 21) + 310; + int var9 = _nct; + + for (int var10 = 0; var6 > var10; ++var10) { + int var11 = _ssH[var10]; + if (var11 > 12) { + var11 = 12; + } + + int var12; + if (var10 == var6 - 1) { + var12 = var7 + 16; + } else { + var12 = var9 == 0 ? 0 : var7 * var11 / var9; + var7 -= var12; + var9 -= var11; + var12 += 21; + } + + if (var6 - 1 == var10) { + if (var3 >= var2 + var5 && var3 < var5 + 32 - var2 + var12) { + return var10; + } + } else if (var5 + var2 <= var3 && var3 < var5 + var2 + var12) { + return var10; + } + + var5 += var12; + } + + } else if (var2 < var4 - 34 && var2 > var4 - 54) { + if (var5 - 5 < var3 && var5 + 17 > var3) { + return -2; + } + + if (var5 + _tvct[this.id] - 45 < var3 && _tvct[this.id] + (var5 - 23) > var3) { + return -3; + } + } + } + return -1; + } + + public void i150() { + if (!ShatteredPlansClient._mdQ && !ShatteredPlansClient._isa) { + while (JagexApplet.nextTypedKey()) { + if (JagexApplet.lastTypedKeyCode == KeyState.Code.ESCAPE) { + if (this.id == Id.PAUSE_SINGLEPLAYER || this.id == Id.PAUSE_MULTIPLAYER_1 || this.id == Id.PAUSE_MULTIPLAYER_2 || this.id == Id.PAUSE_MULTIPLAYER_3) { + switchTo(Id.GAME, 0, false); + } else if (currentMenu != Id.G9) { + final int var2 = _brm; + switchTo(var2, 0, false); + } + } else { + this.k150(); + if (this.inputState.selectedItem != -1) { + this.a520(false, this.inputState.selectedItem); + } + } + } + + if (this.id == Id.INSTRUCTIONS_1 || this.id == Id.INSTRUCTIONS_2) { + this.f423(); + } + + if (this.id == Id.ACHIEVEMENTS) { + this.a150(); + } + + this.inputState.processMouseInput(this.getHoveredItemIndex(JagexApplet.mouseX, JagexApplet.mouseY), this.getHoveredItemIndex(JagexApplet.mousePressX, JagexApplet.mousePressY)); + if (this.inputState.selectedItem != -1) { + this.a520(true, this.inputState.selectedItem); + } + } + + if (this.id == Id.INSTRUCTIONS_1 || this.id == Id.INSTRUCTIONS_2) { + this.d423(); + } + + if (this.id == Id.ACHIEVEMENTS) { + this.a487(); + } + + ++this._h; + if (this.id == Id.ERROR && ++_onc > 32) { + _onc = 32; + } + + if (this.id == Id.RATINGS && ++_nba > 32) { + _nba = 32; + } + } + + private void a150() { + _sbe = this.d313(107, JagexApplet.mouseX, JagexApplet.mouseY); + + if (JagexApplet.mouseButtonJustClicked != MouseState.Button.NONE) { + final int var2 = this.d313(84, JagexApplet.mousePressX, JagexApplet.mousePressY); + if (var2 == _anc) { + _anc = -1; + } else if (var2 != -1) { + _anc = var2; + } + } + + } + + private int b410() { + if (currentMenu != this.id && this.id != nextMenu) { + return 0; + } else if (currentMenu >= 0 && nextMenu >= 0 && currentMenu != nextMenu) { + final int var2 = items[currentMenu].length * widths[currentMenu] + _tvct[currentMenu] + 10; + final int var3 = _tvct[nextMenu] + widths[nextMenu] * items[nextMenu].length + 10; + return MathUtil.ease(_ehQ, 32, var2, var3); + } else { + + return widths[this.id] * items[this.id].length + _tvct[this.id] + 10; + } + } + + private void d093(final int var2) { + _os = var2; + _c = _mgfb != 0 ? MathUtil.ease(_mgfb, 32, _c, _acw) : _acw; + _acw = 0; + + for (int var3 = 0; var3 < var2; ++var3) { + _acw += _cbi[var3]; + } + + _mgfb = 1; + } + + public void g150() { + if (ClientGameSession.playSession != null || ClientGameSession.spectateSession != null) { + a587oa(); + } + + final int var2 = this.c137(); + final int var3 = this.b410(); + final int var4 = this.h137(); + final int var5 = (-var2 + ShatteredPlansClient.SCREEN_WIDTH) / 2; + final int var7 = 20 + var2; + final int var8 = var4 - 10; + final int var9 = var3 + 10; + drawShine(var5, var8, var7, var9); + this.e093(var4, 7903); + } + + private void a520(final boolean var1, final int var2) { + @MagicConstant(valuesFromClass = Item.class) + final int var4 = items[this.id][var2]; + if (this.inputState.isItemActiveAllowRepeat()) { + this.b258(var4, var2, var1); + } + + if (var4 != Item.SINGLE_PLAYER_SKIRMISH + && var4 != Item.START_SKIRMISH + && var4 != Item.ENTER_MULTIPLAYER_LOBBY + && var4 != Item.RETURN_TO_GAME + && var4 != Item.MENU + && var4 != Item.DISCARD + && var4 != Item.ACHIEVEMENTS + && var4 != Item.INSTRUCTIONS_1 + && var4 != Item.INSTRUCTIONS_2 + && var4 != Item.CURRENT_MENU + && var4 != Item.RANKINGS + && var4 != Item.FULLSCREEN + && var4 != Item.END_GAME + && var4 != Item.OFFER_DRAW + && var4 != Item.RESIGN + && var4 != Item.OFFER_REMATCH + && var4 != Item.RETURN_TO_LOBBY + && var4 != Item.HS_MODE_1 + && var4 != Item.HS_MODE_2 + && var4 != Item.HS_MODE_3 + && var4 != Item.RATING_MODE_1 + && var4 != Item.RATING_MODE_2 + && var4 != Item.LOGIN_CREATE_ACCOUNT + && var4 != Item.TUTORIAL + && var4 != Item.QUIT + && var4 != Item.WATCH_INTRODUCTION + && var4 != Item.GAME_TYPE + && var4 != Item.RULE_SET + && var4 != Item.OPTIONS_MENU + && var4 != Item.MUSIC_TRACK) { + final int var6; + final int var7; + final int var8; + if (var4 == Item.SOUND_VOLUME) { + boolean var5 = false; + if (this.inputState.isHomeTyped() && Sounds.soundVolume > 0) { + Sounds.setSoundVolume(0); + var5 = true; + } + + if (this.inputState.isEndTyped() && Sounds.soundVolume < 256) { + var5 = true; + Sounds.setSoundVolume(256); + } + + if (this.inputState.isMouseButtonDown()) { + var6 = this.getX() + this.a527(var2) + _hgt - 120 >> 1; + var7 = JagexApplet.mouseX - var6; + var8 = 256 * var7 / 120; + if (var8 <= 0) { + Sounds.setSoundVolume(0); + } else Sounds.setSoundVolume(Math.min(256, var8)); + + var5 = true; + } + + if (this.inputState.isLeftTyped() && Sounds.soundVolume > 0) { + var5 = true; + c487(); + } + + if (this.inputState.isRightTyped() && Sounds.soundVolume < 256) { + var5 = true; + f423cc(); + } + + if (var5 && (!this.inputState.isMouseButtonDown() || ShatteredPlansClient.currentTick > _tvcq)) { + Sounds.play(Sounds.SFX_FACTORY_NOISE); + _tvcq = 25 + ShatteredPlansClient.currentTick; + } + } else if (var4 == Item.MUSIC_VOLUME) { + if (this.inputState.isHomeTyped()) { + Sounds.setMusicVolume(0); + } + + if (this.inputState.isEndTyped()) { + Sounds.setMusicVolume(256); + } + + if (this.inputState.isMouseButtonDown()) { + var6 = this.getX() - (-this.a527(var2) - _hgt) - 120 >> 1; + var7 = JagexApplet.mouseX - var6; + var8 = 256 * var7 / 120; + if (var8 > 0) { + Sounds.setMusicVolume(Math.min(256, var8)); + } else { + Sounds.setMusicVolume(0); + } + } + + if (this.inputState.isLeftTyped()) { + d487qs(); + } + + if (this.inputState.isRightTyped()) { + a150mgf(); + } + } + } + } + + private void j150() { + final byte var2 = 52; + int var3 = 140; + Drawing.saveBoundsTo(_kcm); + int var4 = var2; + Drawing.a797(); + + boolean var5; + int var6; + Sprite var8; + for (var6 = 0; var6 < 25; ++var6) { + final int var7 = (int) (Math.cos((double) (-(23 * var6)) + Math.PI * (double) (2 * ShatteredPlansClient.currentTick) / 150.0D) * 64.0D) + 64; + var5 = (1 << var6 & unlockedAchievementsBitmap) != 0; + var8 = !var5 ? ShatteredPlansClient._msb : a367(var6); + final Sprite var9 = var5 ? achievementIcon(var6) : ShatteredPlansClient._lqo; + if (_leb != 32) { + var8.drawAdd(var4 - 16, var3 - 16, var7 * _leb / 32); + var9.drawAdd(var4, var3, (_leb << 8) / 32); + } else if (_anc == var6) { + var8 = var5 ? a367dmr(var6) : ShatteredPlansClient._jcnk; + final Sprite bi_ = var5 ? ACHIEVEMENTS[var6] : ShatteredPlansClient._dmgn; + final Sprite var10 = new Sprite(48, 48); + Drawing.saveContext(); + var10.installForDrawing(); + bi_.c115(0, 0, 48, 48); + Drawing.restoreContext(); + var8.c050(var4 - 32, var3 - 32, 96, 96, var7 << 1); + var10.drawAdd(var4 - 8, var3 - 8, 256); + } else if (_sbe != var6) { + if (_anc == -1) { + var8.drawAdd(var4 - 16, var3 - 16, var7); + var9.drawAdd(var4, var3, 256); + } else { + var8.drawAdd(var4 - 16, var3 - 16, var7 >> 1); + var9.drawAdd(var4, var3, 128); + } + } else if (_anc == -1) { + var8.drawAdd(var4 - 16, var3 - 16, var7); + var9.drawAdd(var4, var3, 256); + var9.drawAdd(var4, var3, 128); + } else { + var8.drawAdd(var4 - 16, var3 - 16, var7); + var9.drawAdd(var4, var3, 256); + } + + var4 += 42; + if (var6 % 13 == 12) { + var3 = (int) ((double) var3 + Math.sqrt(3.0D) * 21.0D); + var4 = 73; + } + } + + if (_glh == null) { + _glh = new Sprite(256, 256); + } + + if (_ilgb == null) { + _ilgb = new Sprite(256, 256); + } + + var6 = _anc != -1 ? _anc : _sbe; + var5 = var6 != -1 && (unlockedAchievementsBitmap & 1 << var6) != 0; + final Sprite var28; + if (var5) { + var28 = ACHIEVEMENTS[var6]; + var8 = a367dmr(var6); + } else { + var28 = ShatteredPlansClient._dmgn; + var8 = ShatteredPlansClient._jcnk; + } + + Drawing.saveContext(); + _glh.installForDrawing(); + Drawing.clear(); + var28.b115(0, 0, 256, 256); + _ilgb.installForDrawing(); + var8.c093(0, 0); + Drawing.restoreContext(); + final int var29 = 64 + (int) (64.0D * Math.cos(Math.PI * (double) (ShatteredPlansClient.currentTick * 2) / 150.0D)); + final int var30 = MathUtil.ease(_leb, 32, 0, 600); + final short var11 = 155; + final int var12 = (ShatteredPlansClient.SCREEN_WIDTH - var30) / 2; + final short var13 = 220; + if (var30 > 20) { + drawShine(var12, var13, var30, var11); + } + + Drawing.setBounds(10 + var12, var13, var12 + var30 - 10, 375); + final int var15 = (_tvcm[this.id] >> 1) + 24; + final short var16 = 128; + Drawing.fillRoundedRect(30, var15 + 6, 136, 136, 10, 0, 128); + Drawing.f669(30, 6 + var15, 136, 136, 10, Drawing.alphaOver(0, 3974311, 128)); + _ilgb.c050(-30, var15 - 54, 256, 256, var29); + _glh.c050(34, 10 + var15, var16, 128, 256); + final short var18 = 350; + final int var27 = 24 + this.b474() + this.c137() + 16 - var18; + final short var19 = 136; + final int var20 = -136 + (this.h137() - 34); + Drawing.fillRoundedRect(var27, var20, var18, var19, 10, 0, 128); + Drawing.f669(var27, var20, var18, var19, 10, Drawing.alphaOver(0, 3974311, 128)); + final String var21; + int var23; + int var33; + if (var6 != -1 && var6 != 24) { + FONT.draw(StringConstants.ACHIEVEMENT_NAMES[var6].toUpperCase(), var27 + 10, var20 + 6 + FONT.ascent, 2805974); + var21 = "(" + Strings.format(StringConstants.ORB_POINTS, Integer.toString(_eig[var6])) + ")"; + var33 = SMALL_FONT.drawParagraph(var21, 10 + var27, 14 + var20 + SMALL_FONT.ascent, 330, var19, 2805974, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, SMALL_FONT.ascent); + var33 += 1 + SMALL_FONT.drawParagraph(StringConstants.ACHIEVEMENT_CRITERIA[var6], 10 + var27, SMALL_FONT.ascent / 2 + var20 + 14 + (1 + var33) * SMALL_FONT.ascent, 330, var19, 2805974, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, SMALL_FONT.ascent); + SMALL_FONT.drawParagraph(StringConstants.ACHIEVEMENTS_RATED_ONLY, 10 + var27, var20 - (-14 - (var33 + 1) * SMALL_FONT.ascent), 330, var19, 2805974, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, SMALL_FONT.ascent); + } else if (var6 == 24) { + FONT.draw(StringConstants.ACHIEVEMENT_NAMES[24].toUpperCase(), var27 + 10, 6 + var20 + FONT.ascent, 2805974); + final String var22; + if (var5) { + var21 = "(" + Strings.format(StringConstants.ORB_POINTS, Integer.toString(_eig[24])) + ")"; + var22 = StringConstants.ACHIEVEMENT_CRITERIA[24]; + } else { + var21 = "(" + StringConstants.ORB_POINTS_COLON + "???)"; + var22 = StringConstants.SECRET_ACHIEVEMENT; + } + + var23 = SMALL_FONT.drawParagraph(var21, var27 + 10, 14 + var20 + SMALL_FONT.ascent, 330, var19, 2805974, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, SMALL_FONT.ascent); + var23 += 1 + SMALL_FONT.drawParagraph(var22, 10 + var27, (var23 + 1) * SMALL_FONT.ascent + (var20 - (-14 - SMALL_FONT.ascent / 2)), 330, var19, 2805974, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, SMALL_FONT.ascent); + SMALL_FONT.drawParagraph(StringConstants.ACHIEVEMENTS_RATED_ONLY, var27 + 10, (var23 + 1) * SMALL_FONT.ascent + 14 + var20, 330, var19, 2805974, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, SMALL_FONT.ascent); + } else if (areAchievementsOffline) { + FONT.draw(StringConstants.WARNING.toUpperCase(), 10 + var27, var20 + 6 + FONT.ascent, 2805974); + SMALL_FONT.drawParagraph(StringConstants.ACHIEVEMENTS_OFFLINE, 10 + var27, SMALL_FONT.ascent + var20 + 14, 330, var19, 2805974, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, SMALL_FONT.ascent); + } else { + FONT.draw(StringConstants.TEXT_NO_ACHIEVEMENT.toUpperCase(), var27 + 10, FONT.ascent + 6 + var20, 2805974); + SMALL_FONT.drawParagraph(StringConstants.MOUSE_OVER_AN_ICON, 10 + var27, var20 + 14 + SMALL_FONT.ascent, 330, var19, 2805974, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, SMALL_FONT.ascent); + } + + int var32; + if (_ekA == 0) { + var32 = _qBb; + } else { + var32 = MathUtil.ease(_ekA, 32, _upd, _qBb); + } + + var32 = MathUtil.ease(_leb, 32, 0, var32); + if (var32 > 20) { + final byte var31 = 52; + final int i = 187; + final int i1 = -(var32 >> 1) + var15 + 74; + Drawing.fillRoundedRect(i, i1, var31, var32, 10, 0, 128); + Drawing.f669(i, i1, var31, var32, 10, Drawing.alphaOver(0, 3974311, 128)); + Drawing.setBounds(191, 4 + i1, 235, var32 - 4 + i1); + if (var6 != -1 && (var6 != 24 || var5)) { + var33 = _ndd[var6]; + if (var33 == 1) { + ORB_COIN.c115(197, i1 + ((var32 >> 1) - 16), 32, 32); + } else { + var23 = i1 + 24; + final int var24 = Math.max(var32, 48); + + final int var25 = i1 + var24 - 24; + + for (int var26 = 0; var33 > var26; ++var26) { + ORB_COIN.c115(197, var23 + (var26 * (var25 - var23) / (var33 - 1) - 16), 32, 32); + } + } + } + } + + Drawing.restoreBoundsFrom(_kcm); + } + + private int getX() { + return this.b474() + 65; + } + + private void k150() { + if (JagexApplet.lastTypedKeyCode == KeyState.Code.F1) { + ShatteredPlansClient.drawDebugStats = !ShatteredPlansClient.drawDebugStats; + } + if (JagexApplet.lastTypedKeyCode == KeyState.Code.F2) { + ShatteredPlansClient.renderQuality = RenderQuality.high(); + } + if (JagexApplet.lastTypedKeyCode == KeyState.Code.F3) { + ShatteredPlansClient.renderQuality = RenderQuality.medium(); + } + if (JagexApplet.lastTypedKeyCode == KeyState.Code.F4) { + ShatteredPlansClient.renderQuality = RenderQuality.low(); + } + + if (currentMenu == Id.INSTRUCTIONS_1) { + this.e150(); + } else { + this.inputState.processKeyInputVertical(); + } + } + + private void a316(final int var1, int var3, final int var4, final int var5, final Font var8, final String var9) { + + for (int var12 = 0; var12 < Objects.requireNonNull(GameUI.breakLinesWithColorTags(var8, var9, new int[]{var5})).length; ++var12) { + final String var13 = Objects.requireNonNull(GameUI.breakLinesWithColorTags(var8, var9, new int[]{var5}))[var12]; + var3 += var1; + final int var14 = var8.measureLineWidth(var13); + if (4 * var14 < var5 * 3) { + var8.draw(var13, var4, var3, Drawing.WHITE); + } else { + var8.drawJustified(var13, var4, var3, var5); + } + } + + } + + private void a827(final int var1, final int var3, final int var4, final int var5, final int var6, final int var7) { + final byte var8 = 20; + final byte var9 = 5; + ShatteredPlansClient.a229ch(var6, 7, 24, var1 - 2, var7 - 2 + (var3 - var5), 0, 4 + var5); + if (var4 > 0) { + final int var11 = var3 * var4 / 15 + 10; + Drawing.fillRoundedRect(var1, var3 + (var7 - var11), var8, var11, var9, var6); + int var12 = var11 / 3; + if (var12 <= 10) { + var12 = 11; + } + + Drawing.b370(var1, var3 + (var7 - var11), var8, var12, var9, var6); + final int[] var13 = new int[4]; + Drawing.saveBoundsTo(var13); + Drawing.setBounds(var1, var7, var1 + var8, var3 + var7); + GameView.a835ie(GameView.COMBAT_HEX_WHITE, var1, var7); + Drawing.restoreBoundsFrom(var13); + } + + SMALL_FONT.drawCentered(Integer.toString(var4), 10 + var1, 10 + var7 + var3, Drawing.WHITE); + } + + private void a366(final int var1) { + final int var3 = _ssH.length; + int var4 = _acw + 147; + + int var5; + for (var5 = 0; var5 < var3; ++var5) { + var4 -= _cbi[var5]; + if (var4 < 0) { + break; + } + } + + final int var6 = var5 + var1; + if (var6 >= 0 && _ssH.length > var6) { + this.d093(var6); + } + + } + + private void b258(@MagicConstant(valuesFromClass = Item.class) final int which, final int var1, final boolean var2) { + if (which == Item.SINGLE_PLAYER_SKIRMISH) { + this._g = var1; + switchTo(Id.SKIRMISH_SETUP, nextMenu, var2); + } else if (which == Item.ENTER_MULTIPLAYER_LOBBY) { + if (JagexApplet.isAnonymous) { + showLobbyDialog(StringConstants.PLEASE_LOG_IN, var2, 0); + } else { + this._g = var1; + switchTo(Id.LOADING_LOBBY, nextMenu, var2); + } + } else if (which == Item.RETURN_TO_GAME) { + this._g = var1; + switchTo(Id.GAME, 0, var2); + } else if (which == Item.RANKINGS) { + this._g = var1; + switchTo(Id.RATINGS, nextMenu, var2); + } else if (which == Item.INSTRUCTIONS_1) { + this._g = var1; + switchTo(Id.INSTRUCTIONS_1, nextMenu, var2); + } else if (which == Item.INSTRUCTIONS_2) { + this._g = var1; + switchTo(Id.INSTRUCTIONS_2, nextMenu, var2); + } else if (which == Item.MENU) { + this._g = var1; + switchTo(Id.MAIN, nextMenu, var2); + } else if (which == Item.CURRENT_MENU) { + this._g = var1; + switchTo(_brm, nextMenu, var2); + } else if (which == Item.FULLSCREEN) { + if (ShatteredPlansClient.fullScreenCanvas == null) { + ShatteredPlansClient.accountCreationDisabled = false; + a540fm(var2); + } else { + ShatteredPlansClient.removeFocusLossDetectingCanvas(); + } + } else if (which == Item.END_GAME) { + this._g = var1; + ClientGameSession.playSession.handlePlayerLeft(var2); + ShatteredPlansClient._lgb = true; + ShatteredPlansClient._tli = false; + } else if (which == Item.OFFER_DRAW) { + this._g = var1; + ClientGameSession.playSession.sendOfferDraw(); + switchTo(Id.GAME, 0, var2); + } else if (which == Item.RESIGN) { + this._g = var1; + ClientGameSession.playSession.sendResign(); + switchTo(Id.GAME, 0, var2); + } else if (which == Item.OFFER_REMATCH) { + this._g = var1; + ClientGameSession.playSession.offerRematch(); + switchTo(Id.GAME, 0, var2); + } else if (which == Item.RETURN_TO_LOBBY) { + this._g = var1; + if (ShatteredPlansClient.playingGame) { + switchTo(Id.LEAVE_GAME_TO_LOBBY, nextMenu, var2); + } + if (ShatteredPlansClient.spectatingGame) { + C2SPacket.spectateGame(0); + } + } else if (which == Item.RATING_MODE_1) { + _ffy = 0; + } else if (which == Item.RATING_MODE_2) { + _ffy = 1; + } else if (which == Item.LOGIN_CREATE_ACCOUNT) { + if (this.id == Id.ACHIEVEMENTS || currentMenu == Id.RATINGS) { + ShatteredPlansClient.a776qk(this.id); + } + } else if (which == Item.ACHIEVEMENTS) { + this._g = var1; + switchTo(Id.ACHIEVEMENTS, nextMenu, var2); + } else if (which == Item.DISCARD) { + this._g = var1; + switchTo(Id.MAIN, nextMenu, var2); + discarding = true; + } else if (which == Item.TUTORIAL) { + this._g = var1; + switchTo(Id.TUTORIAL, 0, var2); + } else if (which == Item.QUIT) { + this._g = var1; + JagexApplet.navigateToQuit(JagexBaseApplet.getInstance()); + } else if (which == Item.WATCH_INTRODUCTION) { + switchTo(Id.INTRODUCTION, nextMenu, var2); + } else if (which == Item.GAME_TYPE) { + skirmishGameType = skirmishGameType.next(); + ShatteredPlansClient.MENU_ITEM_LABELS[28] = switch (skirmishGameType) { + case CONQUEST -> StringConstants.TEXT_MAP_HEX; + case CAPTURE_AND_HOLD -> StringConstants.TEXT_MAP_SOL; + case POINTS -> StringConstants.TEXT_MAP_POINTS; + case DERELICTS -> StringConstants.TEXT_MAP_DERELICTS; + case TUTORIAL -> throw new IllegalStateException(); + }; + } else if (which == Item.RULE_SET) { + if (gameOptions == GameOptions.STREAMLINED_GAME_OPTIONS) { + gameOptions = GameOptions.CLASSIC_GAME_OPTIONS; + ShatteredPlansClient.MENU_ITEM_LABELS[29] = StringConstants.TEXT_GARRISON_YES; + } else { + ShatteredPlansClient.MENU_ITEM_LABELS[29] = StringConstants.TEXT_GARRISON_NO; + gameOptions = GameOptions.STREAMLINED_GAME_OPTIONS; + } + } else if (which == Item.START_SKIRMISH) { + this._g = var1; + switchTo(Id.SKIRMISH, 0, var2); + } else if (which == Item.OPTIONS_MENU) { + this._g = var1; + switchTo(Id.OPTIONS, nextMenu, var2); + } else if (which == Item.MUSIC_TRACK) { + //noinspection StringEquality + if (ShatteredPlansClient.MENU_ITEM_LABELS[32] == ShatteredPlansClient.MUSIC_OPT_NEW) { + ShatteredPlansClient.MENU_ITEM_LABELS[32] = ShatteredPlansClient.MUSIC_OPT_OLD; + ShatteredPlansClient.currentTrack = Sounds.MUSIC_IN_GAME_1; + } else { + ShatteredPlansClient.MENU_ITEM_LABELS[32] = ShatteredPlansClient.MUSIC_OPT_NEW; + ShatteredPlansClient.currentTrack = Sounds.MUSIC_IN_GAME_2; + } + + ShatteredPlansClient.a827jo(ShatteredPlansClient.currentTrack, 50, true); + } + } + + public boolean a427() { + if (this.id == Id.RATINGS) { + return --_nba <= 0; + } else if (this.id == Id.ACHIEVEMENTS) { + return --_leb <= 0; + } else if (this.id == Id.ERROR) { + return --_onc <= 0; + } else { + return true; + } + } + + private int h137() { + if (currentMenu == this.id || this.id == nextMenu) { + return nextMenu != currentMenu && currentMenu >= 0 && nextMenu >= 0 ? MathUtil.ease(_ehQ, 32, _tvcm[currentMenu], _tvcm[nextMenu]) : _tvcm[this.id]; + } else { + return 0; + } + } + + private String lookupLabel(@MagicConstant(valuesFromClass = Item.class) final int item) { + String label = ShatteredPlansClient.MENU_ITEM_LABELS[item]; + if (item == Item.GAME_TYPE || item == Item.RULE_SET) { + label = " " + label; + } + + if (item == Item.CURRENT_MENU) { + if (_brm == Id.MAIN || nextMenu == Id.MAIN || _brm == Id.OPTIONS || nextMenu == Id.OPTIONS) { + label = ShatteredPlansClient.MENU_ITEM_LABELS[Item.MENU]; + } else if (_brm == Id.PAUSE_SINGLEPLAYER || nextMenu == Id.PAUSE_SINGLEPLAYER) { + label = StringConstants.PAUSE_MENU; + } else if (_brm == Id.PAUSE_MULTIPLAYER_1 || nextMenu == Id.PAUSE_MULTIPLAYER_1 || _brm == Id.PAUSE_MULTIPLAYER_2 || nextMenu == Id.PAUSE_MULTIPLAYER_2 || _brm == Id.PAUSE_MULTIPLAYER_3 || nextMenu == Id.PAUSE_MULTIPLAYER_3) { + label = StringConstants.OPTIONS_MENU_NOT_PAUSED; + } + } + + if (item == Item.END_GAME && ClientGameSession.playSession != null && ClientGameSession.playSession.isTutorial) { + label = StringConstants.END_TUTORIAL; + } + + return label != null ? label.toUpperCase() : null; + } + + private int c417(final int var1) { + return this.h137() + _tvct[this.id] + widths[this.id] * var1; + } + + @SuppressWarnings("SameParameterValue") + private static void drawLabeledVerticalBracket(final String label, final int labelX, final int labelY, final int labelWidth, final int bracketTipX, final int bracketY1, final int bracketY2, final int bracketWidth, final int color) { + int bracketSpineX = bracketTipX + bracketWidth; + // draw the bracket limbs + if (bracketWidth > 0) { + Drawing.horizontalLine(bracketTipX, bracketY1, bracketWidth, color); + Drawing.horizontalLine(bracketTipX, bracketY2, bracketWidth, color); + } else { + Drawing.horizontalLine(bracketSpineX, bracketY1, -bracketWidth, color); + Drawing.horizontalLine(bracketSpineX, bracketY2, -bracketWidth, color); + } + + final boolean labelIsOutsideBracket; + // draw the bracket spine + if (bracketY2 > bracketY1) { + labelIsOutsideBracket = labelY < bracketY1 || labelY >= bracketY2; + Drawing.verticalLine(bracketSpineX, bracketY1, bracketY2 - bracketY1 + 1, color); + } else { + labelIsOutsideBracket = labelY < bracketY2 || labelY >= bracketY1; + Drawing.verticalLine(bracketSpineX, bracketY2, bracketY1 - bracketY2 + 1, color); + } + + if (bracketSpineX < labelX) { + if (labelIsOutsideBracket) { + // draw the bracket tail + final int bracketTailY = (bracketY1 + bracketY2) / 2; + if (bracketWidth <= 0) { + bracketSpineX += bracketWidth; + Drawing.horizontalLine(bracketSpineX, bracketTailY, -bracketWidth, color); + } else { + Drawing.horizontalLine(bracketSpineX, bracketTailY, bracketWidth, color); + bracketSpineX += bracketWidth; + } + + // draw the vertical pointer + final int verticalPointerHeight = labelY - bracketTailY; + if (verticalPointerHeight > 0) { + Drawing.verticalLine(bracketSpineX, bracketTailY, verticalPointerHeight, color); + } else { + Drawing.verticalLine(bracketSpineX, bracketTailY + verticalPointerHeight, -verticalPointerHeight, color); + } + } + // draw the horizontal pointer + Drawing.horizontalLine(bracketSpineX, labelY, labelX - bracketSpineX, color); + } else { + if (labelIsOutsideBracket) { + // draw the bracket tail + final int bracketTailY = (bracketY1 + bracketY2) / 2; + if (bracketWidth > 0) { + bracketSpineX -= bracketWidth; + Drawing.horizontalLine(bracketSpineX, bracketTailY, bracketWidth, color); + } else { + Drawing.horizontalLine(bracketSpineX, bracketTailY, -bracketWidth, color); + bracketSpineX -= bracketWidth; + } + + // draw the vertical pointer + final int verticalPointerHeight = labelY - bracketTailY; + if (verticalPointerHeight > 0) { + Drawing.verticalLine(bracketSpineX, bracketTailY, verticalPointerHeight, color); + } else { + Drawing.verticalLine(bracketSpineX, bracketTailY + verticalPointerHeight, -verticalPointerHeight, color); + } + } + // draw the horizontal pointer + Drawing.horizontalLine(labelX, labelY, bracketSpineX - labelX, color); + } + + final int lineCount = GameUI.breakLines(label, SMALL_FONT, new int[]{labelWidth}); + SMALL_FONT.drawParagraph( + label, + labelX + 5, + labelY - ((lineCount * SMALL_FONT.ascent) / 2), + labelWidth, + (lineCount * SMALL_FONT.ascent) + SMALL_FONT.descent, + color, + Font.HorizontalAlignment.LEFT, + Font.VerticalAlignment.TOP, + SMALL_FONT.ascent); + } + + private void a346(final int var1, final int var2, final int var3, final boolean var4, final int var6, final int var7, final int var8, final boolean var9) { + final double var10 = Math.sqrt(MathUtil.euclideanDistanceSquared(-var7 + var1, var3 - var6)); + final double var12 = (double) (-var6 + var3) / var10; + final double var14 = (double) (-var7 + var1) / var10; + final int var16 = var6 * 16 + (-var6 + var3) * 16 * var2 / 200; + final int var17 = var2 * 16 * (var1 - var7) / 200 + 16 * var7; + final double var18 = Math.sqrt((var17 - var7 * 16) * (-(var7 * 16) + var17) + (var16 - 16 * var6) * (-(16 * var6) + var16)); + + final double sqrt = Math.sqrt(256 * (-var7 + var1) * (-var7 + var1) + (-var6 + var3) * (-var6 + var3) * 256); + final double var20 = sqrt / 2.0D; + final double var22 = 1.0D / var20; + final double var24 = -(0.2D * (-var20 + var18) * (var18 - var20) * var22) + sqrt / 10.0D; + double var26 = 16 * (var7 - var1); + double var28 = (var6 - var3) * 16; + var26 /= sqrt; + var28 /= sqrt; + final int var30 = (int) (var24 * var26) + var16; + final int var31 = -((int) (var28 * var24)) + var17; + int var35; + if (var12 != 0.0D) { + if (var14 != 0.0D) { + double var33 = 16 * (var1 - var7); + if (var33 < 0.0D) { + var33 = -var33; + } + + var35 = (int) (Math.asin(var33 / sqrt) * 32768.0D / Math.PI); + if (var12 >= 0.0D) { + if (var14 > 0.0D) { + var35 = 65536 - var35; + } + } else if (var14 >= 0.0D) { + var35 += 32768; + } else { + var35 = '耀' - var35; + } + } else if (var12 > 0.0D) { + var35 = 0; + } else { + var35 = 32768; + } + } else if (var14 <= 0.0D) { + var35 = 16384; + } else { + var35 = 49152; + } + + var35 -= 16384; + var35 = var35 + var2 * 7600 / 200 - 3800; + GameView.a194ie((ArgbSprite) (var4 ? GameView.ARROW_SHIP_DAMAGED : GameView.ARROW_SHIP), GameView.ARROW_SHIP.width << 3, GameView.ARROW_SHIP.height << 3, var30, var31, var35, 4096); + if (var9) { + Drawing.fillCircle(var30 >> 4, var31 >> 4, 9, 0, 92); + SMALL_FONT.drawCentered(Integer.toString(var8), var30 >> 4, 4 + (var31 >> 4), Drawing.WHITE); + } + + } + + private int getHoveredItemIndex(final int mouseX, final int mouseY) { + for (int i = 0; i < items[this.id].length; ++i) { + final int var5 = this.c417(i); + if (mouseX >= this.getX() && mouseX < this.a527(i) + && mouseY >= var5 && mouseY < var5 + this.getWidth()) { + return i; + } + } + + return -1; + } + + private void e150() { + if (JagexApplet.lastTypedKeyCode == KeyState.Code.PAGE_UP) { + this.a366(-1); + } else if (JagexApplet.lastTypedKeyCode == KeyState.Code.PAGE_DOWN) { + this.a366(1); + } else if (JagexApplet.lastTypedKeyCode == KeyState.Code.HOME) { + this.d093(0); + } else if (JagexApplet.lastTypedKeyCode == KeyState.Code.END) { + this.d093(_ssH.length - 1); + } + + this.inputState.processKeyInputVertical(); + } + + private int c137() { + if (currentMenu != this.id && this.id != nextMenu) { + return 0; + } else if (nextMenu == currentMenu) { + return _tvcr[currentMenu]; + } else if (currentMenu >= 0 && nextMenu >= 0) { + return MathUtil.ease(_ehQ, 32, _tvcr[currentMenu], _tvcr[nextMenu]); + } else { + double var2 = MathUtil.ease(_ehQ, 32); + if (this.id == currentMenu) { + var2 = -var2 + 1.0D; + } + + return (int) ((double) _tvcr[this.id] * var2); + } + } + + public static final int NUM_GROUPS = 14; + + @SuppressWarnings("WeakerAccess") + public static final class Id { + public static final int GAME = -1; + public static final int LOBBY = -2; + public static final int INTRODUCTION = -3; + public static final int SKIRMISH = -4; + public static final int TUTORIAL = -5; + public static final int LOADING_LOBBY = -6; + public static final int LEAVE_GAME_TO_LOBBY = -7; + public static final int MAIN = 0; + public static final int PAUSE_SINGLEPLAYER = 1; + public static final int PAUSE_MULTIPLAYER_1 = 2; + public static final int PAUSE_MULTIPLAYER_2 = 3; + public static final int PAUSE_MULTIPLAYER_3 = 4; + public static final int RATINGS = 5; + public static final int INSTRUCTIONS_1 = 6; + public static final int INSTRUCTIONS_2 = 7; + public static final int ACHIEVEMENTS = 8; + public static final int G9 = 9; + public static final int ERROR = 10; + public static final int SKIRMISH_SETUP = 12; + public static final int OPTIONS = 13; + } + + @SuppressWarnings("WeakerAccess") + public static final class Item { + public static final int SINGLE_PLAYER_SKIRMISH = 0; + public static final int ENTER_MULTIPLAYER_LOBBY = 1; + public static final int RETURN_TO_GAME = 2; + public static final int RANKINGS = 4; + public static final int INSTRUCTIONS_1 = 5; + public static final int INSTRUCTIONS_2 = 6; + public static final int FULLSCREEN = 7; + public static final int MENU = 8; + public static final int CURRENT_MENU = 9; + public static final int END_GAME = 10; + public static final int OFFER_DRAW = 11; + public static final int RESIGN = 12; + public static final int OFFER_REMATCH = 13; + public static final int RETURN_TO_LOBBY = 14; + public static final int HS_MODE_1 = 15; + public static final int HS_MODE_2 = 16; + public static final int HS_MODE_3 = 17; + public static final int RATING_MODE_1 = 18; + public static final int RATING_MODE_2 = 19; + public static final int QUIT = 20; + public static final int SOUND_VOLUME = 21; + public static final int MUSIC_VOLUME = 22; + public static final int ACHIEVEMENTS = 23; + public static final int LOGIN_CREATE_ACCOUNT = 24; + public static final int DISCARD = 25; + public static final int TUTORIAL = 26; + public static final int WATCH_INTRODUCTION = 27; + public static final int GAME_TYPE = 28; + public static final int RULE_SET = 29; + public static final int START_SKIRMISH = 30; + public static final int OPTIONS_MENU = 31; + public static final int MUSIC_TRACK = 32; + } + + public enum DialogOption { + ACCEPT, TRY_AGAIN, MEMBERS, CLOSE + } + + public enum FullscreenDialog { + MEMBERS_ONLY_NOT_LOGGED_IN, MEMBERS_ONLY_LOGGED_IN, ACCEPT_COUNTDOWN, UNAVAILABLE, LOST_FOCUS, TIMEOUT + } +} diff --git a/src/main/java/funorb/shatteredplans/client/MessagePumpThread.java b/src/main/java/funorb/shatteredplans/client/MessagePumpThread.java new file mode 100644 index 0000000..35dd023 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/MessagePumpThread.java @@ -0,0 +1,314 @@ +package funorb.shatteredplans.client; + +import funorb.awt.GraphicsBackend; +import funorb.awt.MouseControlBackend; +import funorb.cache.CacheFile; +import funorb.client.JagexBaseApplet; +import funorb.shatteredplans.CacheFiles; +import funorb.client.pa_; +import funorb.util.PseudoMonotonicClock; +import org.intellij.lang.annotations.MagicConstant; + +import java.awt.Component; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Toolkit; +import java.awt.datatransfer.Transferable; +import java.awt.event.ActionEvent; +import java.io.DataInputStream; +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.URL; + +public final class MessagePumpThread implements Runnable { + public static final String GAME_ID = "shatteredplans"; + public static final String JAVA_VENDOR = System.getProperty("java.vendor"); + public static final String JAVA_VERSION = System.getProperty("java.version"); + private static final String OS_NAME = System.getProperty("os.name"); + private static final String OS_NAME_LOWER_CASE = OS_NAME.toLowerCase(); + private static final String USER_HOME; + private static final String[] PREFERENCE_FILE_SEARCH_DIRS; + public static MessagePumpThread instance; + + static { + final String userHome = System.getProperty("user.home"); + USER_HOME = userHome == null ? "~/" : userHome + "/"; + PREFERENCE_FILE_SEARCH_DIRS = new String[]{"c:/rscache/", "/rscache/", USER_HOME, "c:/windows/", "c:/winnt/", "c:/", "/tmp/", ""}; + } + + private final Thread thread; + private final GraphicsBackend graphicsBackend = new GraphicsBackend(); + private final MouseControlBackend mouseControlBackend = new MouseControlBackend(); + private EventQueue eventQueue; + public CacheFiles cacheFiles; + private boolean isShutdownRequested = false; + private MailboxMessage mailboxHead = null; + private MailboxMessage mailboxTail = null; + + public MessagePumpThread() throws Exception { + try { + this.eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); + } catch (final Throwable var11) { + } + + this.cacheFiles = new CacheFiles(); + + this.thread = new Thread(this); + this.thread.setPriority(10); + this.thread.setDaemon(true); + this.thread.start(); + } + + private static CacheFile openPreferencesCache(final String name, final String suffix) { + final String filename = "jagex_" + name + "_preferences" + suffix + ".dat"; + for (final String dir : PREFERENCE_FILE_SEARCH_DIRS) { + if (dir.length() == 0 || (new File(dir)).exists()) { + try { + return new CacheFile(new File(dir, filename), 10000L); + } catch (final Exception var8) { + } + } + } + return null; + } + + public void postEvent(final Object source) { + if (this.eventQueue != null) { + for (int i = 0; i < 50 && this.eventQueue.peekEvent() != null; ++i) { + JagexBaseApplet.maybeSleep(1L); + } + + try { + if (source != null) { + this.eventQueue.postEvent(new ActionEvent(source, ActionEvent.ACTION_FIRST, "dummy")); + } + } catch (final Exception e) {} + } + } + + public MailboxMessage sendGetDeclaredMethodMessage(final Class targetClass, final String methodName, final Class[] paramType) { + return this.sendMessage(MailboxMessage.Type.GET_DECLARED_METHOD, new Object[]{targetClass, methodName, paramType}, 0, 0); + } + + public MailboxMessage sendSpawnThreadMessage(final Runnable target, final int priority) { + return this.sendMessage(MailboxMessage.Type.SPAWN_THREAD, target, priority, 0); + } + + public MailboxMessage sendOpenSocketMessage(final String var3, final int var2) { + return this.sendMessage(MailboxMessage.Type.OPEN_SOCKET, var3, var2, 0); + } + + public MailboxMessage sendEnterFullScreenMessage(final int bitDepth) { + return this.sendMessage(MailboxMessage.Type.ENTER_FULL_SCREEN, null, 41943520, (bitDepth << 16)); + } + + public MailboxMessage sendOpenUrlStreamMessage(final URL var1) { + return this.sendMessage(MailboxMessage.Type.OPEN_URL_STREAM, var1, 0, 0); + } + + private MailboxMessage sendMessage( + @MagicConstant(valuesFromClass = MailboxMessage.Type.class) final int type, + final Object opayload, + final int ipayload1, + final int ipayload2) { + final MailboxMessage msg = new MailboxMessage(); + msg.type = type; + msg.opayload = opayload; + msg.ipayload1 = ipayload1; + msg.ipayload2 = ipayload2; + synchronized (this) { + if (this.mailboxTail == null) { + this.mailboxTail = this.mailboxHead = msg; + } else { + this.mailboxTail.next = msg; + this.mailboxTail = msg; + } + + this.notify(); + return msg; + } + } + + private MailboxMessage receiveMessage() { + final MailboxMessage msg; + synchronized (this) { + while (true) { + if (this.isShutdownRequested) { + return null; + } + + if (this.mailboxHead != null) { + msg = this.mailboxHead; + this.mailboxHead = this.mailboxHead.next; + if (this.mailboxHead == null) { + this.mailboxTail = null; + } + break; + } + + try { + this.wait(); + } catch (final InterruptedException ignored) { + } + } + } + return msg; + } + + @Override + public void run() { + while (true) { + final MailboxMessage msg = this.receiveMessage(); + if (msg == null) return; // shutdown requested + + try { + switch (msg.type) { + case MailboxMessage.Type.OPEN_SOCKET -> { + if (PseudoMonotonicClock.currentTimeMillis() < 0L) { + throw new IOException(); + } + msg.response = new Socket(InetAddress.getByName((String) msg.opayload), msg.ipayload1); + } + case MailboxMessage.Type.SPAWN_THREAD -> { + final Thread var24 = new Thread((Runnable) msg.opayload); + var24.setDaemon(true); + var24.start(); + var24.setPriority(msg.ipayload1); + msg.response = var24; + } + case MailboxMessage.Type.DNS_REVERSE_LOOKUP -> { + if (PseudoMonotonicClock.currentTimeMillis() < 0L) { + throw new IOException(); + } + + final String var14 = (255 & msg.ipayload1 >> 24) + "." + ((16756253 & msg.ipayload1) >> 16) + "." + ((msg.ipayload1 & ''') >> 8) + "." + (255 & msg.ipayload1); + msg.response = InetAddress.getByName(var14).getHostName(); + } + case MailboxMessage.Type.OPEN_URL_STREAM -> { + if (PseudoMonotonicClock.currentTimeMillis() < 0L) { + throw new IOException(); + } + msg.response = new DataInputStream(((URL) msg.opayload).openStream()); + } + case MailboxMessage.Type.LIST_DISPLAY_MODES -> msg.response = this.graphicsBackend.listmodes(); + case MailboxMessage.Type.ENTER_FULL_SCREEN -> { + final Frame frame = new Frame("Jagex Full Screen"); + msg.response = frame; + frame.setResizable(false); + this.graphicsBackend.enter(frame, msg.ipayload1 >>> 16, msg.ipayload1 & 0xffff, msg.ipayload2 >> 16, msg.ipayload2 & 0xffff); + } + case MailboxMessage.Type.EXIT_FULL_SCREEN -> this.graphicsBackend.exit(); + case MailboxMessage.Type.GET_DECLARED_METHOD -> { + final Object[] var15 = (Object[]) msg.opayload; + if (((Class) var15[0]).getClassLoader() == null) { + throw new SecurityException(); + } + + msg.response = ((Class) var15[0]).getDeclaredMethod((String) var15[1], (Class[]) var15[2]); + } + case MailboxMessage.Type.GET_DECLARED_FIELD -> { + final Object[] var15 = (Object[]) msg.opayload; + if (((Class) var15[0]).getClassLoader() == null) { + throw new SecurityException(); + } + + msg.response = ((Class) var15[0]).getDeclaredField((String) var15[1]); + } + case MailboxMessage.Type.OPEN_GAME_PREFERENCES_CACHE -> + msg.response = openPreferencesCache(GAME_ID, (String) msg.opayload); + case MailboxMessage.Type.OPEN_GLOBAL_PREFERENCES_CACHE -> + msg.response = openPreferencesCache("", (String) msg.opayload); + case MailboxMessage.Type.MOVE_MOUSE -> this.mouseControlBackend.movemouse(msg.ipayload1, msg.ipayload2); + case MailboxMessage.Type.SHOW_CURSOR -> + this.mouseControlBackend.showcursor((Component) msg.opayload, msg.ipayload1 != 0); + case MailboxMessage.Type.WINDOWS_START -> { + try { + if (!OS_NAME_LOWER_CASE.startsWith("win")) { + throw new Exception(); + } + + final String var14 = (String) msg.opayload; + if (!var14.startsWith("http://") && !var14.startsWith("https://")) { + throw new Exception(); + } + + final String var17 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789?&=,.%+-_#:/*"; + + for (int var5 = 0; var5 < var14.length(); ++var5) { + if (var17.indexOf(var14.charAt(var5)) == -1) { + throw new Exception(); + } + } + + Runtime.getRuntime().exec("cmd /c start \"j\" \"" + var14 + "\""); + msg.response = null; + } catch (final Exception var10) { + msg.response = var10; + throw var10; + } + } + case MailboxMessage.Type.SET_CUSTOM_CURSOR -> { + final Object[] payload = (Object[]) msg.opayload; + this.mouseControlBackend.setcustomcursor((Component) payload[0], (int[]) payload[1], msg.ipayload1, msg.ipayload2, (java.awt.Point) payload[2]); + } + case MailboxMessage.Type.GET_CLIPBOARD -> + msg.response = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null); + case MailboxMessage.Type.SET_CLIPBOARD -> + Toolkit.getDefaultToolkit().getSystemClipboard().setContents((Transferable) msg.opayload, null); + case MailboxMessage.Type.DNS_LOOKUP -> { + if (PseudoMonotonicClock.currentTimeMillis() < 0L) { + throw new IOException(); + } + msg.response = InetAddress.getByName((String) msg.opayload).getAddress(); + } + case MailboxMessage.Type.A287 -> { + if (PseudoMonotonicClock.currentTimeMillis() < 0L) { + throw new IOException(); + } + msg.response = pa_.a287ho(msg.ipayload1, (String) msg.opayload).b693(); + } + default -> throw new Exception("unknown message type"); + } + + msg.status = MailboxMessage.Status.SUCCESS; + } catch (final ThreadDeath var11) { + throw var11; + } catch (final Throwable var12) { + msg.status = MailboxMessage.Status.FAILURE; + } + + //noinspection SynchronizationOnLocalVariableOrMethodParameter + synchronized (msg) { + msg.notify(); + } + } + } + + public void shutdown() { + synchronized (this) { + this.isShutdownRequested = true; + this.notifyAll(); + } + + try { + this.thread.join(); + } catch (final InterruptedException var8) {} + try { + this.cacheFiles.close(); + } catch (final IOException e) {} + } + + public MailboxMessage sendExitFullScreenMessage(final Frame var1) { + return this.sendMessage(MailboxMessage.Type.EXIT_FULL_SCREEN, var1, 0, 0); + } + + public MailboxMessage sendListDisplayModesMessage() { + return this.sendMessage(MailboxMessage.Type.LIST_DISPLAY_MODES, null, 0, 0); + } + + public MailboxMessage sendGetDeclaredFieldMessage(final Class var1, final String var3) { + return this.sendMessage(MailboxMessage.Type.GET_DECLARED_FIELD, new Object[]{var1, var3}, 0, 0); + } +} diff --git a/src/main/java/funorb/shatteredplans/client/RenderQuality.java b/src/main/java/funorb/shatteredplans/client/RenderQuality.java new file mode 100644 index 0000000..1ae3805 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/RenderQuality.java @@ -0,0 +1,40 @@ +package funorb.shatteredplans.client; + +import org.intellij.lang.annotations.MagicConstant; + +public final class RenderQuality { + public final boolean antialiasWormholeConnections; + public final boolean antialiasStarfieldBackground; + @MagicConstant(valuesFromClass = Level.class) + public final int statsScreenFadeQuality; + @MagicConstant(valuesFromClass = Level.class) + public final int transitionQuality; + + private RenderQuality(final boolean antialiasWormholeConnections, + final boolean antialiasStarfieldBackground, + @MagicConstant(valuesFromClass = Level.class) final int statsScreenFadeQuality, + @MagicConstant(valuesFromClass = Level.class) final int transitionQuality) { + this.antialiasWormholeConnections = antialiasWormholeConnections; + this.antialiasStarfieldBackground = antialiasStarfieldBackground; + this.statsScreenFadeQuality = statsScreenFadeQuality; + this.transitionQuality = transitionQuality; + } + + public static RenderQuality low() { + return new RenderQuality(false, false, Level.LOW, Level.LOW); + } + + public static RenderQuality medium() { + return new RenderQuality(true, false, Level.MEDIUM, Level.MEDIUM); + } + + public static RenderQuality high() { + return new RenderQuality(true, true, Level.HIGH, Level.HIGH); + } + + public static final class Level { + public static final int LOW = 0; + public static final int MEDIUM = 1; + public static final int HIGH = 2; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/ShatteredPlansClient.java b/src/main/java/funorb/shatteredplans/client/ShatteredPlansClient.java new file mode 100644 index 0000000..f04ec07 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/ShatteredPlansClient.java @@ -0,0 +1,4972 @@ +package funorb.shatteredplans.client; + +import funorb.Strings; +import funorb.audio.AudioThread; +import funorb.audio.MusicTrack; +import funorb.audio.SampledAudioChannel; +import funorb.audio.h_; +import funorb.audio.vk_; +import funorb.awt.FullScreenCanvas; +import funorb.awt.KeyState; +import funorb.awt.MouseState; +import funorb.cache.CacheWorker; +import funorb.cache.ResourceLoader; +import funorb.client.AchievementRequest; +import funorb.client.EmailLoginCredentials; +import funorb.client.GetProfileRequest; +import funorb.client.JagexBaseApplet; +import funorb.client.LoginState; +import funorb.client.RankingsRequest; +import funorb.client.ReflectionRequest; +import funorb.client.SetProfileRequest; +import funorb.client.TemplateDictionary; +import funorb.client.UserIdLoginCredentials; +import funorb.client.intro.JagexLogoIntroAnimation; +import funorb.client.lobby.ActionButton; +import funorb.client.lobby.AddOrRemovePlayerPopup; +import funorb.client.lobby.ChatMessage; +import funorb.client.lobby.ChatMessage.Channel; +import funorb.client.lobby.ClientLobbyRoom; +import funorb.client.lobby.Component; +import funorb.client.lobby.ContextMenu; +import funorb.client.lobby.LobbyPlayer; +import funorb.client.lobby.PlayerListEntry; +import funorb.client.lobby.PopupMenu; +import funorb.client.lobby.QuickChatHelpPanel; +import funorb.client.lobby.ReportAbuseDialog; +import funorb.client.lobby.ScrollPane; +import funorb.client.lobby.TabbedPlayerListWrapper; +import funorb.client.lobby.vm_; +import funorb.commonui.CommonUI; +import funorb.commonui.form.DobToEnableChatForm; +import funorb.graphics.ArgbSprite; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.graphics.NineSliceSprite; +import funorb.graphics.Sprite; +import funorb.graphics.SpriteResource; +import funorb.io.HuffmanCoder; +import funorb.shatteredplans.C2SPacket; +import funorb.shatteredplans.S2CPacket; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.game.ClientGameSession; +import funorb.shatteredplans.client.game.GameView; +import funorb.shatteredplans.client.intro.IntroAnimation; +import funorb.shatteredplans.game.GameOptions; +import funorb.shatteredplans.game.GameState; +import funorb.shatteredplans.game.ai.TutorialAI2; +import funorb.shatteredplans.map.StarSystem; +import funorb.shatteredplans.map.TannhauserUnconnectedException; +import funorb.shatteredplans.map.generator.MapGenerationFailure; +import funorb.util.MathUtil; +import funorb.util.PseudoMonotonicClock; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.sound.sampled.LineUnavailableException; +import java.awt.Canvas; +import java.io.IOException; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Queue; +import java.util.Random; + +import static funorb.shatteredplans.S2CPacket.Type; + +public final class ShatteredPlansClient extends JagexApplet { + public static final int SCREEN_WIDTH = 640; + public static final int SCREEN_HEIGHT = 480; + public static final int[] NUM_PLAYERS_OPTION_VALUES = {2, 3, 4, 5, 6}; + public static final int[] GAMEOPT_CHOICES_COUNTS = {5, 7, 4, 5, 2}; + public static final Random globalRandom = new Random(); + private static final int _hoc = 0x808080; + private static final int _gnt = 0; + private static final StringBuilder typedChatMessage = new StringBuilder(80); + private static final int[][] _msc = new int[][]{{2, 1, 3, 4}, {2, 1, 3, 3}, {2, 1, 3, 1}, {2, 1, 3, 0}}; + public static boolean _mdQ; + public static Sprite _fmb; + public static int _tga; + public static boolean isChatboxSelected = true; + public static RenderQuality renderQuality; + public static boolean debugModeEnabled; + private static Sprite _jfa; + public static int _vjC; + public static Sprite _wab; + private static Component> _few; + private static Component> _abAb; + public static Component chatMessageLabel; + public static boolean invitePlayersDialogOpen; + private static boolean _ucB; + public static final int STATUS_MESSAGE_TIMEOUT_DURATION = 150; + private static Component _erj; + private static boolean areAchievementsInitialized; + public static AchievementRequest achievementRequest; + private static Component> _faX; + private static int _pgJ; + private static String playerWhoKickedYou; + private static long cannotStartGameUntil; + private static int joinRequestCount; + private static boolean findOpponentsButtonClicked; + private static int _tmh = 0; + private static Component HIDE_CHAT_TEMPORARILY_LABEL; + private static Component> invitePlayersDialogContents; + public static String currentServerName; + private static int _flf = 360; + public static Sprite LOSE_SPRITE; + public static boolean isQuickChatOpen = false; + private static Component _mbn; + private static int[][] _peD; + public static String[][] GAMEOPT_TOOLTIPS; + public static long localPlayerId; + public static ClientLobbyRoom unratedLobbyRoom; + private static byte[] playerSeatsFilledBitmap; + private static boolean justRecievedRoomDetailsFromServer; + private static int[] _cfa; + private static int _dmgm = SCREEN_HEIGHT; + public static final String[] STAT_NAMES = new String[16]; + public static final String[] STAT_DESCS = new String[16]; + private static final int _jlU = 4; + public static final int SCREEN_CENTER_X = SCREEN_WIDTH / 2; + public static final int SCREEN_CENTER_Y = SCREEN_HEIGHT / 2; + public static int chatMessageCount; + private static boolean inLobbyBrowser; + public static int unratedLobbyRoomTransitionCounter; + private static int playerRating; + public static vm_ _dmrh; + public static ScrollPane currentContextMenuParent; + private static Sprite BEAKER; + public static Sprite LOGO; + public static Sprite _dmgn; + public static Sprite _lqo; + private static Sprite LOBBY_ICON; + private static boolean[] _ekF; + public static ChatMessage[] chatMessages; + private static boolean loadedProfile; + private static GetProfileRequest request = null; + private static int allowSpectateSelection; + public static int lobbyBrowserTransitionCounter; + private static TabbedPlayerListWrapper lobbyRoomTabbedPlayerList; + public static Component> invitePlayersDialog; + private static Component> lobbyRoomLeftPanel; + public static Sprite _jcnk; + public static Sprite _msb; + public static long _tkz; + public static String _cvco; + private static int _cvcm = 0; + public static boolean _cvcn = false; + private static boolean leavingLobby; + public static int ratedLobbyRoomTransitionCounter; + public static int _vsd; + public static boolean _lgb; + public static boolean showYouHaveBeenKickedDialog; + private static boolean _nsob; + public static boolean spectatingGame; + private static boolean _hmo = true; + public static int previousS2cPacketType = -1; + public static int _kpi; + private static boolean _cjx; + /** + * The type of a partially recieved incoming packet. A value of + * {@code -1} indicates that we have not recieved the type of the next packet. + */ + private static int nextS2cPacketType = -1; + public static int currentS2cPacketType = -1; + public static int secondPreviousS2cPacketType = -1; + public static int thirdPreviousS2cPacketType = -1; + private static boolean _sbh; + public static boolean _isa; + public static MusicTrack currentTrack; + public static String MUSIC_OPT_NEW; + public static String MUSIC_OPT_OLD; + public static boolean accountCreationDisabled; + public static boolean _tli; + public static String networkErrorMessage; + private static boolean returnToMainMenuClicked; + public static int currentTick; + public static @NotNull Channel _tlr = Channel.LOBBY; + private static byte[] _lrc; + public static boolean drawDebugStats; + public static FullScreenCanvas fullScreenCanvas; + public static TemplateDictionary templateDictionary; + private static int _ssw; + private static boolean _wgd; + public static Sprite _bga; + private static ClientLobbyRoom ratedLobbyRoom; + private static byte[] gameoptChoicesBitmap; + private static int maxAiPlayersSelection; + public static Sprite STAR_FIELD; + public static Sprite WIN_SPRITE; + public static int[] _imb; + public static String[] MENU_ITEM_LABELS; + public static boolean playingGame; + public static @NotNull Channel currentChatChannel = Channel.LOBBY; + public static int _flh; + private static Component _cbl; + private static boolean _K = true; + private static boolean menuInitialized; + private static boolean isFullyLoaded; + private static int someCounterResetEvery200Ticks = 200; + private static int _ebb = 0; + private static EnumJbg _jbg = EnumJbg.C0; + @MagicConstant(valuesFromClass = Menu.Id.class) + private static int initialMenu; + private static int ticksSinceLastMouseEventAtStartOfTick; + private static Component _cka; + private static int _naF = 0; + private final Queue achievementNotifications = new ArrayDeque<>(); + private int achievementNotificationTimer = 0; + + public static boolean a788(final long playerId, final String playerName) { + final PlayerListEntry entry = PlayerListEntry.lookupFriend(playerName); + if (entry == null || entry.serverName == null) { + return unratedLobbyRoom != null && LobbyPlayer.getJoined(playerId) != null; + } else { + return true; + } + } + + public static void resetFrameClock() { + frameClock.reset(); + Arrays.fill(recentFrameTimes, 0L); + framesToAdvance = 0; + } + + private static void n423() { + if (Menu.currentMenu != Menu.Id.INTRODUCTION && ClientGameSession.playSession == null && ClientGameSession.spectateSession == null) { + a034so((SCREEN_WIDTH - LOGO.offsetX) / 2, 10, _jfa); + LOGO.drawAdd((SCREEN_WIDTH - LOGO.offsetX) / 2, 10, 256); + } + } + + private static void a111qf() { + if (ContextMenu.openInstance != null && ContextMenu.openInstance.view.f427()) { + dismissContextMenu(); + } else if (ReportAbuseDialog.openInstance != null && ReportAbuseDialog.openInstance.h154()) { + ReportAbuseDialog.openInstance = null; + dismissContextMenu(); + } else if (AddOrRemovePlayerPopup.openInstance == null || !AddOrRemovePlayerPopup.openInstance.f427()) { + a111ph(); + } + } + + private static void initializeUiStrings() { + if (MENU_ITEM_LABELS == null) { + MUSIC_OPT_NEW = StringConstants.MUSIC_COLON + StringConstants.TRACK_NAME_NEW; + MUSIC_OPT_OLD = StringConstants.MUSIC_COLON + StringConstants.TRACK_NAME_OLD; + + MENU_ITEM_LABELS = new String[33]; + MENU_ITEM_LABELS[Menu.Item.SINGLE_PLAYER_SKIRMISH] = StringConstants.TEXT_SKIRMISH; + MENU_ITEM_LABELS[Menu.Item.ENTER_MULTIPLAYER_LOBBY] = StringConstants.ENTER_MULTIPLAYER_LOBBY; + MENU_ITEM_LABELS[Menu.Item.RETURN_TO_GAME] = StringConstants.RETURN_TO_GAME; + MENU_ITEM_LABELS[Menu.Item.RANKINGS] = StringConstants.RANKINGS; + MENU_ITEM_LABELS[Menu.Item.INSTRUCTIONS_1] = StringConstants.INSTRUCTIONS; + MENU_ITEM_LABELS[Menu.Item.INSTRUCTIONS_2] = StringConstants.INSTRUCTIONS; + MENU_ITEM_LABELS[Menu.Item.FULLSCREEN] = StringConstants.FULLSCREEN; + MENU_ITEM_LABELS[Menu.Item.MENU] = StringConstants.MENU; + MENU_ITEM_LABELS[Menu.Item.CURRENT_MENU] = null; + MENU_ITEM_LABELS[Menu.Item.END_GAME] = StringConstants.END_GAME; + MENU_ITEM_LABELS[Menu.Item.RESIGN] = StringConstants.RESIGN; + MENU_ITEM_LABELS[Menu.Item.RETURN_TO_LOBBY] = StringConstants.RETURN_TO_LOBBY; + MENU_ITEM_LABELS[Menu.Item.HS_MODE_1] = StringConstants.HS_MODE_NAMES[0]; + MENU_ITEM_LABELS[Menu.Item.HS_MODE_2] = StringConstants.HS_MODE_NAMES[1]; + MENU_ITEM_LABELS[Menu.Item.HS_MODE_3] = StringConstants.HS_MODE_NAMES[2]; + MENU_ITEM_LABELS[Menu.Item.RATING_MODE_1] = StringConstants.RATING_MODE_NAMES[0]; + MENU_ITEM_LABELS[Menu.Item.RATING_MODE_2] = StringConstants.RATING_MODE_NAMES[1]; + MENU_ITEM_LABELS[Menu.Item.QUIT] = StringConstants.QUIT; + MENU_ITEM_LABELS[Menu.Item.SOUND_VOLUME] = StringConstants.SOUND_COLON; + MENU_ITEM_LABELS[Menu.Item.MUSIC_VOLUME] = StringConstants.MUSIC_COLON; + MENU_ITEM_LABELS[Menu.Item.ACHIEVEMENTS] = StringConstants.ACHIEVEMENTS; + MENU_ITEM_LABELS[Menu.Item.LOGIN_CREATE_ACCOUNT] = StringConstants.LOGIN_CREATE_ACCOUNT; + MENU_ITEM_LABELS[Menu.Item.DISCARD] = StringConstants.DISCARD; + MENU_ITEM_LABELS[Menu.Item.TUTORIAL] = StringConstants.TUTORIAL; + MENU_ITEM_LABELS[Menu.Item.WATCH_INTRODUCTION] = StringConstants.WATCH_INTRODUCTION; + MENU_ITEM_LABELS[Menu.Item.GAME_TYPE] = StringConstants.TEXT_MAP_HEX; + MENU_ITEM_LABELS[Menu.Item.RULE_SET] = StringConstants.TEXT_GARRISON_NO; + MENU_ITEM_LABELS[Menu.Item.START_SKIRMISH] = StringConstants.START_SKIRMISH; + MENU_ITEM_LABELS[Menu.Item.OPTIONS_MENU] = StringConstants.OPTIONS_MENU_NOT_PAUSED; + MENU_ITEM_LABELS[Menu.Item.MUSIC_TRACK] = MUSIC_OPT_NEW; + + STAT_NAMES[ 0] = StringConstants.TEXT_STAT_MAX_TOTAL_FLEET_SIZE; + STAT_NAMES[ 1] = StringConstants.TEXT_STAT_SHIPS_DESTROYED; + STAT_NAMES[ 2] = StringConstants.TEXT_STAT_SHIPS_LOST; + STAT_NAMES[ 3] = StringConstants.TEXT_STAT_AVG_MOVE_SIZE; + STAT_NAMES[ 4] = StringConstants.TEXT_STAT_MAX_PRODUCTION; + STAT_NAMES[ 5] = StringConstants.TEXT_STAT_SHIPS_CONSTRUCTED; + STAT_NAMES[ 6] = StringConstants.TEXT_STAT_PROJECTS_USED; + STAT_NAMES[ 7] = StringConstants.TEXT_STAT_RESEARCH_WASTED; + STAT_NAMES[ 8] = StringConstants.TEXT_STAT_ATTACKS_SUCCESSFUL; + STAT_NAMES[ 9] = StringConstants.TEXT_STAT_ATTACKS_FAILED; + STAT_NAMES[10] = StringConstants.TEXT_STAT_DEFENCES_SUCCESSFUL; + STAT_NAMES[11] = StringConstants.TEXT_STAT_DEFENCES_FAILED; + STAT_NAMES[12] = StringConstants.TEXT_STAT_EFFICIENCY; + STAT_NAMES[13] = StringConstants.TEXT_STAT_FLUIDITY; + STAT_NAMES[14] = StringConstants.TEXT_STAT_AGGRESSIVENESS; + STAT_NAMES[15] = StringConstants.TEXT_STAT_SOLIDITY; + + STAT_DESCS[ 0] = StringConstants.TEXT_STAT_DESC_MAX_TOTAL_FLEET_SIZE; + STAT_DESCS[ 1] = StringConstants.TEXT_STAT_DESC_SHIPS_DESTROYED; + STAT_DESCS[ 2] = StringConstants.TEXT_STAT_DESC_SHIPS_LOST; + STAT_DESCS[ 3] = StringConstants.TEXT_STAT_DESC_AVG_MOVE_SIZE; + STAT_DESCS[ 4] = StringConstants.TEXT_STAT_DESC_MAX_PRODUCTION; + STAT_DESCS[ 5] = StringConstants.TEXT_STAT_DESC_SHIPS_CONSTRUCTED; + STAT_DESCS[ 6] = StringConstants.TEXT_STAT_DESC_PROJECTS_USED; + STAT_DESCS[ 7] = StringConstants.TEXT_STAT_DESC_RESEARCH_WASTED; + STAT_DESCS[ 8] = StringConstants.TEXT_STAT_DESC_ATTACKS_SUCCESSFUL; + STAT_DESCS[ 9] = StringConstants.TEXT_STAT_DESC_ATTACKS_FAILED; + STAT_DESCS[10] = StringConstants.TEXT_STAT_DESC_DEFENCES_SUCCESSFUL; + STAT_DESCS[11] = StringConstants.TEXT_STAT_DESC_DEFENCES_FAILED; + STAT_DESCS[12] = StringConstants.TEXT_STAT_DESC_EFFICIENCY; + STAT_DESCS[13] = StringConstants.TEXT_STAT_DESC_FLUIDITY; + STAT_DESCS[14] = StringConstants.TEXT_STAT_DESC_AGGRESSIVENESS; + STAT_DESCS[15] = StringConstants.TEXT_STAT_DESC_SOLIDITY; + + StringConstants.GAMEOPT_NAMES[0] = new String[5]; + GAMEOPT_TOOLTIPS = new String[5][]; + GAMEOPT_TOOLTIPS[0] = new String[5]; + for (int i = 0; i < 5; ++i) { + StringConstants.GAMEOPT_NAMES[0][i] = Integer.toString(i); + GAMEOPT_TOOLTIPS[0][i] = StringConstants.TEXT_TOTAL_PLAYERS; + } + GAMEOPT_TOOLTIPS[2] = StringConstants.GAME_TYPE_TOOLTIPS; + GAMEOPT_TOOLTIPS[4] = StringConstants.RULESET_TOOLTIPS; + } + } + + private static String loadingMessage(final ResourceLoader loader, final String group, final String waiting, final String loading) { + return loader.isIndexLoaded() ? loading + " - " + loader.percentLoaded(group) + "%" : waiting; + } + + public static String loadingMessage(final ResourceLoader loader, final String waiting, final String loading) { + return loader.isIndexLoaded() ? loading + " - " + loader.percentLoaded() + "%" : waiting; + } + + private static String loadingMessage0(final ResourceLoader loader, final String waiting, final String loading) { + return loader.isIndexLoaded() ? loading + " - " + loader.percentLoaded(0) + "%" : waiting; + } + + public static void a776qk(@MagicConstant(valuesFromClass = Menu.Id.class) final int id) { + _jbg = EnumJbg.C1; + initialMenu = id; + } + + private static void tickSomethingThatSeemsRelatedToAudio() { + Sounds.musicChannel.doSomethingThatSeemsRelatedToAudio(); + Sounds.soundsChannel.doSomethingThatSeemsRelatedToAudio(); + + --someCounterResetEvery200Ticks; + if (someCounterResetEvery200Ticks == 0) { + someCounterResetEvery200Ticks = 200; + Sounds.playingSounds.removeIf(sound -> !sound._p.isLinked()); + } + } + + private static void a780ck(final ResourceLoader commonSpriteLoader, + final ResourceLoader commonFontLoader, + final ResourceLoader spriteLoader, + final ResourceLoader fontLoader) { + Menu.FONT = SpriteResource.loadPalettedSpriteFont(spriteLoader, fontLoader, "", "font"); + Menu.SMALL_FONT = SpriteResource.loadPalettedSpriteFont(spriteLoader, fontLoader, "", "smallfont"); + + LOGO = SpriteResource.loadSprite(spriteLoader, "logo"); + final int var7 = 3 * LOGO.offsetX / 4; + final int var8 = LOGO.offsetY * 3 / 4; + Drawing.saveContext(); + _jfa = new Sprite(var7, var8); + _jfa.installForDrawing(); + Drawing.fillRect(0, 0, var7, var8, Drawing.WHITE); + LOGO.e326(0, 0, 0); + Drawing.b669(3, 3, var7, var8); + LOGO.e326(0, 0, 255); + Drawing.restoreContext(); + + Menu.MENU_HEX = SpriteResource.loadSprite(spriteLoader, "menu_hex"); + Menu.INSTR_MAIN_VIEW = SpriteResource.loadSprite(spriteLoader, "", "instr_mainview"); + Menu.INSTR_STAR_FRAME = SpriteResource.loadSprite(spriteLoader, "", "instr_starframe"); + + final Sprite[] hudIcons = SpriteResource.loadSprites(spriteLoader, "", "hud_icons"); + GameUI.HUD_ICON_1 = hudIcons[0]; + GameUI.HUD_ICON_2 = hudIcons[1]; + GameUI.HUD_ICON_3 = hudIcons[2]; + GameUI.HUD_ICON_4 = hudIcons[3]; + GameUI.HUD_ICON_5 = hudIcons[4]; + final Sprite[] hudIconsRed = SpriteResource.loadSprites(spriteLoader, "", "hud_icons_red"); + GameUI.HUD_ICON_RED_1 = hudIconsRed[0]; + GameUI.HUD_ICON_RED_2 = hudIconsRed[1]; + GameUI.HUD_ICON_RED_3 = hudIconsRed[2]; + GameUI.HUD_ICON_RED_4 = hudIconsRed[3]; + GameUI.HUD_ICON_RED_5 = hudIconsRed[4]; + final Sprite[] hudIconsNoBase = SpriteResource.loadSprites(spriteLoader, "", "hud_icons_nobase"); + GameUI.HUD_ICON_NO_BASE_1 = hudIconsNoBase[0]; + GameUI.HUD_ICON_NO_BASE_2 = hudIconsNoBase[1]; + GameUI.HUD_ICON_NO_BASE_3 = hudIconsNoBase[2]; + GameUI.HUD_ICON_NO_BASE_4 = hudIconsNoBase[3]; + GameUI.HUD_ICON_NO_BASE_5 = hudIconsNoBase[4]; + + GameUI.ICON_CIRCLES = SpriteResource.loadSprites(spriteLoader, "", "icon_circles"); + GameUI.PRODUCTION_ICONS = SpriteResource.loadSprites(spriteLoader, "", "production_icons"); + GameUI.PRODUCTION_BUTTON = SpriteResource.loadSprite(spriteLoader, "production_button"); + GameUI.PRODUCTION_BUTTON_DOWN = SpriteResource.loadSprite(spriteLoader, "production_button_down"); + GameUI.PROJECT_ICONS = SpriteResource.loadSprites(spriteLoader, "", "project_icons"); + + GameUI.FACTION_ICONS = SpriteResource.loadSprites(spriteLoader, "", "faction_icons"); + GameUI.FACTION_ICONS_LARGE = SpriteResource.loadSprites(spriteLoader, "", "faction_icons_large"); + final Sprite tmp1 = GameUI.FACTION_ICONS[1]; + GameUI.FACTION_ICONS[1] = GameUI.FACTION_ICONS[5]; + GameUI.FACTION_ICONS[5] = tmp1; + final Sprite tmp2 = GameUI.FACTION_ICONS[2]; + GameUI.FACTION_ICONS[2] = GameUI.FACTION_ICONS[4]; + GameUI.FACTION_ICONS[4] = tmp2; + final Sprite tmp3 = GameUI.FACTION_ICONS_LARGE[1]; + GameUI.FACTION_ICONS_LARGE[1] = GameUI.FACTION_ICONS_LARGE[5]; + GameUI.FACTION_ICONS_LARGE[5] = tmp3; + final Sprite tmp4 = GameUI.FACTION_ICONS_LARGE[2]; + GameUI.FACTION_ICONS_LARGE[2] = GameUI.FACTION_ICONS_LARGE[4]; + GameUI.FACTION_ICONS_LARGE[4] = tmp4; + + GameUI.READY_BUTTON = SpriteResource.loadSprite(spriteLoader, "ready_button"); + GameUI.READY_BUTTON_DOWN = SpriteResource.loadSprite(spriteLoader, "ready_button_down"); + Menu.SHINE_LEFT = SpriteResource.loadSprite(spriteLoader, "shine_left"); + Menu.SHINE_RIGHT = SpriteResource.loadSprite(spriteLoader, "shine_right"); + Menu.SHINE_MID = SpriteResource.loadSprite(spriteLoader, "shine_mid"); + + GameView.COMBAT_HEX_WHITE = SpriteResource.loadSprite(spriteLoader, "combat_hex_white"); + Drawing.saveContext(); + GameView.COMBAT_HEX_WHITE.installForDrawing(); + GameView.COMBAT_HEX_WHITE.drawTinted2(0, 0, 2105376); + Drawing.restoreContext(); + + StarSystem.PLANET_BURNT = SpriteResource.loadSprite(spriteLoader, "planet_burnt"); + StarSystem.PLANET_SCORCHED_EARTH = SpriteResource.loadSprite(spriteLoader, "planet_scorchedearth"); + StarSystem.PLANET_EARTH_LIKE = SpriteResource.loadSprite(spriteLoader, "planet_earthlike"); + StarSystem.PLANET_EXOTIC = SpriteResource.loadSprite(spriteLoader, "planet_exotic"); + StarSystem.PLANET_GAS = SpriteResource.loadSprite(spriteLoader, "planet_gas"); + StarSystem.PLANET_RINGED = SpriteResource.loadSprite(spriteLoader, "planet_ringed"); + StarSystem.PLANET_ROCK = SpriteResource.loadSprite(spriteLoader, "planet_rock"); + + StarSystem.ALIEN_MINER = SpriteResource.loadSprite(spriteLoader, "alien_miner"); + StarSystem.ALIEN_SHIP = SpriteResource.loadSprite(spriteLoader, "alien_ship"); + StarSystem.ALIEN_BASE = SpriteResource.loadSprite(spriteLoader, "alien_base"); + + GameUI.SHIP = SpriteResource.loadSprite(spriteLoader, "", "ship"); + + GameView.SHIELD = SpriteResource.loadSprite(spriteLoader, "", "shield"); + GameView.DEFENSE_GRID = SpriteResource.loadSprite(spriteLoader, "", "defensegrid"); + GameView.CHEVRON = SpriteResource.loadSprite(spriteLoader, "", "chevron"); + GameView.WARNING = SpriteResource.loadSprite(spriteLoader, "warning"); + GameView.HAMMER = SpriteResource.loadSprite(spriteLoader, "", "hammer"); + + BEAKER = SpriteResource.loadSprite(spriteLoader, "", "beaker"); + + GameUI.FACTION_RING = SpriteResource.loadSprite(spriteLoader, "factionring"); + GameUI.FACTION_RING_TAG = SpriteResource.loadSprite(spriteLoader, "factionringtag"); + GameUI.FACTION_RING_CENTER = SpriteResource.loadSprite(spriteLoader, "factionringcentre"); + + GameView.ARROW_SHIP = SpriteResource.loadSprite(spriteLoader, "arrowship"); + GameView.ARROW_SHIP_DAMAGED = SpriteResource.loadSprite(spriteLoader, "arrowshipdamaged"); + + GameView.FLEETS_ARROW_SHIP = SpriteResource.loadSprite(spriteLoader, "fleetsarrowship"); + GameView.FLEET_BUTTONS = SpriteResource.loadSprites(spriteLoader, "", "fleetbuttons"); + + GameUI.ANIM_ICONS = SpriteResource.loadSprites(spriteLoader, "", "anim_icons"); + + GameView._cos = new ArgbSprite(6, 6); + GameView._cos.pixels[ 0] = 0; + GameView._cos.pixels[ 1] = 0; + GameView._cos.pixels[ 2] = 0x33ffffff; + GameView._cos.pixels[ 3] = 0x22ffffff; + GameView._cos.pixels[ 4] = 0; + GameView._cos.pixels[ 5] = 0; + GameView._cos.pixels[ 6] = 0; + GameView._cos.pixels[ 7] = 0xffa2a2a2; + GameView._cos.pixels[ 8] = 0xffc7c7c7; + GameView._cos.pixels[ 9] = 0xffaeaeae; + GameView._cos.pixels[10] = 0xff545454; + GameView._cos.pixels[11] = 0; + GameView._cos.pixels[12] = 0x10000000; + GameView._cos.pixels[13] = 0xffa9a9a9; + GameView._cos.pixels[14] = 0xffc5c5c5; + GameView._cos.pixels[15] = 0xffb2b2b2; + GameView._cos.pixels[16] = 0xff5d5d5d; + GameView._cos.pixels[17] = 0x44000000; + GameView._cos.pixels[18] = 0x20000000; + GameView._cos.pixels[19] = 0xff707070; + GameView._cos.pixels[20] = 0xff909090; + GameView._cos.pixels[21] = 0xff666666; + GameView._cos.pixels[22] = 0xff2a2a2a; + GameView._cos.pixels[23] = 0x48000000; + GameView._cos.pixels[24] = 0; + GameView._cos.pixels[25] = 0xff323232; + GameView._cos.pixels[26] = 0xff2b2b2b; + GameView._cos.pixels[27] = 0xff1d1d1d; + GameView._cos.pixels[28] = 0xff202020; + GameView._cos.pixels[29] = 0; + GameView._cos.pixels[30] = 0; + GameView._cos.pixels[31] = 0; + GameView._cos.pixels[32] = 503316480; + GameView._cos.pixels[33] = 0x1bffffff; + GameView._cos.pixels[34] = 0; + GameView._cos.pixels[35] = 0; + + GameView.RES_SIDES = new ArgbSprite[6]; + GameView.RES_LOWS = new ArgbSprite[6]; + for (int i = 0; i < GameView.RES_SIDES.length; ++i) { + GameView.RES_SIDES[i] = SpriteResource.loadSprite(spriteLoader, "res_side_" + i); + GameView.RES_LOWS[i] = SpriteResource.loadSprite(spriteLoader, "res_low_" + i); + } + + GameView.DEFNET_ANIM_SMALL = SpriteResource.loadSprites(spriteLoader, "", "defnet_anim_small"); + for (int i = 0; i < GameView.DEFNET_ANIM_SMALL[0].pixels.length; ++i) { + if (GameView.DEFNET_ANIM_SMALL[0].pixels[i] != 0) { + GameView.DEFNET_ANIM_SMALL[0].pixels[i] = ((GameView.DEFNET_ANIM_SMALL[0].pixels[i] >>> 24) / 4 << 24) + 0x5ba8cc; + } + } + for (int i = 1; i < 13; ++i) { + final Sprite frame = GameView.DEFNET_ANIM_SMALL[i]; + for (int j = 0; j < frame.pixels.length; ++j) { + if ((frame.pixels[j] & 0xff000000) == 0) { + frame.pixels[j] = 0; + } + } + } + + GameView.DEFNET_ANIM_MID = SpriteResource.loadSprites(spriteLoader, "", "defnet_anim_mid"); + for (int i = 0; i < GameView.DEFNET_ANIM_MID[0].pixels.length; ++i) { + if (GameView.DEFNET_ANIM_MID[0].pixels[i] != 0) { + GameView.DEFNET_ANIM_MID[0].pixels[i] = 0x5ba8cc + ((GameView.DEFNET_ANIM_MID[0].pixels[i] >>> 24) / 4 << 24); + } + } + for (int i = 1; i < 13; ++i) { + final Sprite frame = GameView.DEFNET_ANIM_MID[i]; + for (int j = 0; j < frame.pixels.length; ++j) { + if ((frame.pixels[j] & 0xff000000) == 0) { + frame.pixels[j] = 0; + } + } + } + + GameView.DEFNET_ANIM_LARGE = SpriteResource.loadSprites(spriteLoader, "", "defnet_anim_large"); + for (int i = 0; i < GameView.DEFNET_ANIM_LARGE[0].pixels.length; ++i) { + if (GameView.DEFNET_ANIM_LARGE[0].pixels[i] != 0) { + GameView.DEFNET_ANIM_LARGE[0].pixels[i] = ((GameView.DEFNET_ANIM_LARGE[0].pixels[i] >>> 24) / 4 << 24) + 0x5ba8cc; + } + } + for (int i = 1; i < 13; ++i) { + final Sprite frame = GameView.DEFNET_ANIM_LARGE[i]; + for (int j = 0; frame.pixels.length > j; ++j) { + if ((frame.pixels[j] & 0xff000000) == 0) { + frame.pixels[j] = 0; + } + } + } + + final Sprite _rfk = new Sprite(16, 10); + final Sprite _b = new Sprite(18, 12); + Drawing.saveContext(); + _rfk.installForDrawing(); + GameUI.SHIP.d093(0, 0); + _b.installForDrawing(); + _rfk.drawTinted2(1, 1, 8421504); + _fmb = new Sprite(10, 12); + _fmb.installForDrawing(); + GameView.SHIELD.drawTinted2(1, 1, 8421504); + final Sprite _eff = new Sprite(12, 12); + _eff.installForDrawing(); + GameView.DEFENSE_GRID.drawTinted2(1, 1, 8421504); + final Sprite _mjKb = new Sprite(12, 12); + _mjKb.installForDrawing(); + GameView.CHEVRON.drawTinted2(1, 1, 8421504); + _wab = new Sprite(128, 128); + _wab.installForDrawing(); + GameView.WARNING.draw(0, 0); + + for (int var13 = 0; var13 < _wab.pixels.length; ++var13) { + if (_wab.pixels[var13] != 0) { + Drawing.addPixel(var13 % _wab.width, var13 / _wab.width, Drawing.WHITE, 128); + _wab.pixels[var13] = _wab.pixels[var13] | -16777216; + } + } + + final Sprite clrVb = new Sprite(18, 12); + clrVb.installForDrawing(); + GameView.HAMMER.drawTinted2(1, 1, 0x808080); + Drawing.restoreContext(); + + _b.f150(Drawing.WHITE); + _fmb.f150(Drawing.WHITE); + _eff.f150(Drawing.WHITE); + _mjKb.f150(Drawing.WHITE); + clrVb.f150(Drawing.WHITE); + Menu._kjf = a113hl(); + + IntroAnimation.spriteLoader = spriteLoader; + Menu.buttonSprite = new NineSliceSprite(generateButtonSlices()); + Menu.ORB_COIN = SpriteResource.loadSprite(commonSpriteLoader, "basic", "orbcoin"); + a714jc(SpriteResource.loadSprite(commonSpriteLoader, "basic", JagexApplet.membershipLevel > 0 ? "unachieved" : "locked")); + Menu.ACHIEVEMENTS = SpriteResource.loadSprites(spriteLoader, "", "achievements"); + Menu._gvsb = new Sprite[Menu.ACHIEVEMENTS.length]; + Menu._vha = new Sprite[Menu.ACHIEVEMENTS.length]; + Menu.ACHIEVEMENT_ICONS = new Sprite[Menu.ACHIEVEMENTS.length]; + + GameView.SYSTEM_ICONS = SpriteResource.loadSprites(spriteLoader, "", "system_icons"); + a174ca(commonSpriteLoader, commonFontLoader, spriteLoader); + GameUI._R = new Sprite(15, 15); + Drawing.saveContext(); + GameUI._R.installForDrawing(); + Drawing.fillCircle(15, 15, 15, 65793); + Drawing.fillCircle(15, 15, 5, 0); + final Sprite _led = new Sprite(15, 20); + _led.installForDrawing(); + Drawing.fillRect(0, 0, 15, 20, 65793); + Drawing.fillCircle(0, -1, 5, 0); + Drawing.fillCircle(0, 20, 5, 0); + final Sprite var22 = SpriteResource.loadSprite(spriteLoader, "", "menu_pip"); + final Sprite _kfle = new Sprite(2 + var22.width, 2 + var22.height); + _kfle.installForDrawing(); + var22.e326(1, 1, 65793); + _bga = new Sprite(21, 22); + _bga.installForDrawing(); + + for (int var16 = 0; var16 < 20; ++var16) { + final int var17 = var16 > 10 ? 20 - var16 : 3; + Drawing.horizontalLine(11 - var17, 1 + var16, 2 * var17, 65793); + } + + Drawing.restoreContext(); + _kfle.f150(2458760); + _bga.f150(2458760); + Menu._ok = _bga.copy(); + Menu._ok.b797(); + + } + + private static void a874b(final Component var0, final Component var2) { + if (_cka == null) { + isChatboxSelected = false; + final String var5; + if (JagexApplet.cannotChat) { + var5 = StringConstants.DOB_CHAT_DISABLED; + } else if (JagexApplet.canOnlyQuickChat) { + var5 = StringConstants.PRESS_F10_TO_QUICK_CHAT; + } else { + var5 = StringConstants.PRESS_TAB_TO_CHAT; + } + + a790cq(_hoc, null, var5, 0); + _cka = chatMessageLabel; + chatMessageLabel._ab = -(8355711 & _hoc >> 1) + _hoc + ((16711422 & Component.UNSELECTED_LABEL._ab) >> 1); + chatMessageLabel.mouseOverTextColor = -(8355711 & _hoc >> 1) + _hoc + ((Component.UNSELECTED_LABEL.mouseOverTextColor & 16711422) >> 1); + _erj = Component._cgC; + chatMessageLabel._qb = -(_hoc >> 1 & 8355711) + _hoc + (Component.UNSELECTED_LABEL._qb >> 1 & 8355711); + _faX = new Component<>(null); + _mbn = new Component<>(var2); + _few = new Component<>(null); + _abAb = new Component<>(null); + chatMessageLabel = new Component<>(var0); + chatMessageLabel.font = Component.CHAT_FONT; + _abAb.addChild(chatMessageLabel); + Component._cgC = new Component<>(_erj); + _abAb.addChild(Component._cgC); + HIDE_CHAT_TEMPORARILY_LABEL = new Component<>(Component.UNSELECTED_LABEL, StringConstants.TAB_HIDE_CHAT_TEMPORARILY); + _cbl = new Component<>(Component.UNSELECTED_LABEL); + _faX.addChild(_mbn); + _faX.addChild(_few); + _few.addChild(_abAb); + _few.addChild(HIDE_CHAT_TEMPORARILY_LABEL); + _few.addChild(_cbl); + } + } + + private static void a430cf(final boolean mouseNotYetHandled) { + tickLobbyListStatuses(); + final int minJoinedPlayerCount = debugModeEnabled ? 0 : 2; + final boolean canStartUnratedGame = unratedLobbyRoom != null && unratedLobbyRoom.joinedPlayerCount >= minJoinedPlayerCount; + tickLobbyInterface(ticksSinceLastMouseEventAtStartOfTick > 50, mouseWheelRotation, mouseNotYetHandled, playingGame || spectatingGame, canStartUnratedGame); +// if (ClientGameSession.isAutoPlaying && _cln % 50 == 0) { +// C2SPacket.send58(); +// } + + if (findOpponentsButtonClicked) { + C2SPacket.send58(); + findOpponentsButtonClicked = false; + } + + if (returnToMainMenuClicked) { + C2SPacket.leaveLobby(); + returnToMainMenuClicked = false; + } + + if (_ucB) { + Menu.showLobbyDialog(StringConstants.RATED_MEMBERS_ONLY, true, 1); + _ucB = false; + } + } + + private static void tickLobbyInterface(final boolean mouseStill, final int mouseWheelRotation, boolean mouseNotYetHandled, final boolean inGame, final boolean canStartUnratedGame) { + ClientLobbyRoom.currentTooltip = null; + tickYouHaveBeenKickedDialog(); + mouseNotYetHandled = tickPopups(mouseNotYetHandled); + tickLobbyRightPanel(mouseNotYetHandled, mouseStill, mouseWheelRotation, inGame, canStartUnratedGame); + tickPlayerLists(mouseStill, mouseWheelRotation); + a778cc(mouseNotYetHandled, mouseWheelRotation); + } + + private static void tickPlayerLists(final boolean mouseStill, final int mouseWheelRotation) { + final PlayerListEntry clickedEntry = tickFriendList(mouseStill, mouseWheelRotation); + if (clickedEntry != null) { + ContextMenu.openInstance.addPlayerItems(false); + ContextMenu.openInstance.view.addItem(StringConstants.MU_LOBBY_FRIEND_RM, ContextMenu.ClickAction.REMOVE_FRIEND); + ContextMenu.openInstance.view.positionRelativeToTarget(mousePressX, mousePressY); + } + tickIgnoreList(mouseStill, mouseWheelRotation); + } + + private static void tickYouHaveBeenKickedDialog() { + if (playerWhoKickedYou != null) { + final String message = Strings.format(StringConstants.YOU_HAVE_BEEN_REMOVED_FROM_XS_GAME, playerWhoKickedYou); + showYouHaveBeenKickedDialog = true; + Component.YOU_HAVE_BEEN_KICKED_LABEL.label = message; + final int width = JagexBaseApplet.screenBuffer.width; + final int height = JagexBaseApplet.screenBuffer.height; + final int messageHeight = Component.YOU_HAVE_BEEN_KICKED_LABEL.font.measureParagraphHeight(message, 272, Component.YOU_HAVE_BEEN_KICKED_LABEL._Y); + final int var4 = height / 2 - (messageHeight / 2) - 110 + 7; + Component.YOU_HAVE_BEEN_KICKED_DIALOG.setBounds((width - 320) / 2, var4, 320, -(2 * var4) + (height - 120)); + Component.YOU_HAVE_BEEN_KICKED_DIALOG.nineSliceSprites = Component.createGradientOutlineSprites(Component.YOU_HAVE_BEEN_KICKED_DIALOG.height, 0xb0b0b0, 0x808080, 0x202020); + Component.YOU_HAVE_BEEN_KICKED_LABEL.setBounds(24, 16, Component.YOU_HAVE_BEEN_KICKED_DIALOG.width - 24 - 24, Component.YOU_HAVE_BEEN_KICKED_DIALOG.height - 24 - 20); + Component.YOU_HAVE_BEEN_KICKED_OK_BUTTON.setBounds(120, Component.YOU_HAVE_BEEN_KICKED_DIALOG.height - 20 - 24, 80, 24); + playerWhoKickedYou = null; + } + } + + private static void a877u(final boolean var0) { + if (Menu.currentMenu == Menu.Id.INTRODUCTION) { + IntroAnimation.render(); + } else if (ClientGameSession.playSession != null) { + a430u(var0); + } else if (ClientGameSession.spectateSession == null) { + f423fr(); + } else { + a430u(var0); + } + } + + private static void a430u(final boolean var1) { + if (ClientGameSession.playSession != null) { + ClientGameSession.playSession.render(); + } + + if (ClientGameSession.spectateSession != null) { + ClientGameSession.spectateSession.render(); + } + + if (_cjx && _tli) { + final boolean var2 = playingGame && isChatboxSelected; + a813qr(var1 && !var2 && a154vc()); + if (playingGame && isChatboxSelected) { + a877rad(var1 && a154vc()); + } + } + } + + public static void clearChatMessages() { + for (int i = 0; i < chatMessageCount; ++i) { + chatMessages[i] = null; + } + chatMessageCount = 0; + } + + private static void a985no(final Canvas canvas) { + if (JagexApplet.loadStage < LoadStage.REQUEST_GAME_STRINGS) { + final boolean var3 = JagexBaseApplet._oqe; + if (JagexBaseApplet._oqe) { + JagexBaseApplet._oqe = false; + } + drawLoadingScreen(loadingScreenMessage(), loadingScreenPercent(), var3); + } else if (!JagexLogoIntroAnimation.isFinished()) { + Drawing.clear(); + JagexLogoIntroAnimation.draw(); + JagexBaseApplet.paint(canvas); + } else if (connectionState == ConnectionState.NOT_CONNECTED) { + a630gr(false); + JagexBaseApplet.paint(canvas); + } else { + CommonUI.drawLoading(); + JagexBaseApplet.paint(canvas); + } + } + + private static String loadingScreenMessage() { + if (JagexApplet.loadStage < 2) { + return connectingToUpdateServerMessage; + } else if (ResourceLoader.COMMON_STRINGS != null) { + return ResourceLoader.COMMON_STRINGS.isIndexLoaded() ? loadingTextMessage : waitingForTextMessage; + } else if (!ResourceLoader.COMMON_SPRITES.isIndexLoaded()) { + return StringConstants.WAITING_FOR_GRAPHICS; + } else if (!ResourceLoader.COMMON_SPRITES.loadGroupData("commonui")) { + return StringConstants.LOADING_GRAPHICS + " - " + ResourceLoader.COMMON_SPRITES.percentLoaded("commonui") + "%"; + } else if (!ResourceLoader.COMMON_FONTS.isIndexLoaded()) { + return StringConstants.WAITING_FOR_FONTS; + } else if (!ResourceLoader.COMMON_FONTS.loadGroupData("commonui")) { + return StringConstants.LOADING_FONTS + " - " + ResourceLoader.COMMON_FONTS.percentLoaded("commonui") + "%"; + } else if (ResourceLoader.JAGEX_LOGO_ANIMATION.isIndexLoaded()) { + return ResourceLoader.JAGEX_LOGO_ANIMATION.loadAllGroups() + ? StringConstants.PLEASE_WAIT + : StringConstants.LOADING_EXTRA_DATA + " - " + ResourceLoader.JAGEX_LOGO_ANIMATION.percentLoaded() + "%"; + } else { + return StringConstants.WAITING_FOR_EXTRA_DATA; + } + } + + private static int loadingScreenPercent() { + if (JagexApplet.loadStage < 2) { + return 0; + } else if (JagexApplet.langId == 0) { + if (!ResourceLoader.COMMON_SPRITES.isIndexLoaded()) { + return 20; + } else if (!ResourceLoader.COMMON_SPRITES.loadGroupData("commonui")) { + return 40; + } else if (!ResourceLoader.COMMON_FONTS.isIndexLoaded()) { + return 50; + } else if (!ResourceLoader.COMMON_FONTS.loadGroupData("commonui")) { + return 60; + } else if (!ResourceLoader.JAGEX_LOGO_ANIMATION.isIndexLoaded()) { + return 70; + } else if (ResourceLoader.JAGEX_LOGO_ANIMATION.loadAllGroups()) { + return 100; + } else { + return 80; + } + } else { + if (ResourceLoader.COMMON_STRINGS != null) { + if (!ResourceLoader.COMMON_STRINGS.isIndexLoaded()) { + return 14; + } else if (!ResourceLoader.COMMON_STRINGS.hasGroup("")) { + return 29; + } else if (!ResourceLoader.COMMON_STRINGS.loadGroupData("")) { + return 29; + } + } + if (!ResourceLoader.COMMON_SPRITES.isIndexLoaded()) { + return 43; + } else if (!ResourceLoader.COMMON_SPRITES.loadGroupData("commonui")) { + return 57; + } else if (!ResourceLoader.COMMON_FONTS.isIndexLoaded()) { + return 71; + } else if (!ResourceLoader.COMMON_FONTS.loadGroupData("commonui")) { + return 80; + } else if (!ResourceLoader.JAGEX_LOGO_ANIMATION.isIndexLoaded()) { + return 82; + } else if (ResourceLoader.JAGEX_LOGO_ANIMATION.loadAllGroups()) { + return 100; + } else { + return 86; + } + } + } + + public static void removeFocusLossDetectingCanvas() { + if (fullScreenCanvas != null) { + JagexApplet.detachFromCanvas(fullScreenCanvas); + fullScreenCanvas.repeatedlyTryToExitFullScreen(); + fullScreenCanvas = null; + canvas.requestFocus(); + } + } + + private static void tickLobbyRightPanel(final boolean mouseNotYetHandled, final boolean var1, final int var4, final boolean inGame, final boolean canStartUnratedGame) { + if (!inGame + && (Component.lastLayoutWidth != Drawing.width || Component.lastLayoutHeight != Drawing.height) + && Drawing.height == JagexBaseApplet.screenBuffer.height + && Drawing.width == JagexBaseApplet.screenBuffer.width) { + if (unratedLobbyRoom != null) { + layoutLobbyRoom(false); + } else if (ratedLobbyRoom == null) { + Component.layoutLobbyBrowser(); + } else { + layoutLobbyRoom(true); + } + } + + if (inGame) { + _tmh = _gnt; + } else { + _tmh = (Component.lastLayoutWidth - SCREEN_WIDTH) / 2; + } + + tickLobbyTransitionCounters(inGame); + if (lobbyBrowserTransitionCounter > 0) { + tickLobbyBrowser(mouseNotYetHandled, inGame); + } + + Component.WAITING_TO_START_LABEL.textAlignment = Font.HorizontalAlignment.CENTER; + Component.WAITING_TO_START_LABEL._kb = Component.LABEL_DARK_1._kb; + if (ratedLobbyRoomTransitionCounter > 0) { + tickRatedLobbyRoom(mouseNotYetHandled, inGame); + } + if (unratedLobbyRoomTransitionCounter > 0) { + tickUnratedLobbyRoom(mouseNotYetHandled, canStartUnratedGame, inGame); + } + + if (invitePlayersDialogOpen && unratedLobbyRoom.maxPlayerCount <= unratedLobbyRoom.joinedPlayerCount) { + Component.INVITE_PLAYER_LIST_SCROLL_PANE.viewport.label = StringConstants.GAME_FULL; + Component.INVITE_PLAYER_LIST_PANEL.enabled = false; + crunch(Component.INVITE_PLAYER_LIST_SCROLL_PANE.content); + } else { + Component.INVITE_PLAYER_LIST_PANEL.enabled = true; + Component.INVITE_PLAYER_LIST_SCROLL_PANE.viewport.label = null; + tickLobbyRoomPlayersTable(var4, Component.INVITE_PLAYER_LIST_SCROLL_PANE, var1); + } + + ClientLobbyRoom.tick(var1, var4); + tickLobbyRoomPlayersTable(var4, Component.JOINED_PLAYERS_TABLE, var1); + ++_ssw; + } + + private static String playerRemovalReasonMessage(final int which, final String who) { + return switch (which) { + case LobbyPlayer.Status.ENTERED_GAME -> Strings.format(StringConstants.MU_X_ENTERED_GAME, who); + case LobbyPlayer.Status.JOINED_YOUR_GAME -> Strings.format(StringConstants.MU_X_JOINED_YOUR_GAME, who); + case LobbyPlayer.Status.ENTERED_OTHER_GAME -> Strings.format(StringConstants.MU_X_ENTERED_OTHER_GAME, who); + case LobbyPlayer.Status.LEFT_LOBBY -> Strings.format(StringConstants.MU_X_LEFT_LOBBY, who); + case LobbyPlayer.Status.LOST_CON -> Strings.format(StringConstants.MU_X_LOST_CON, who); + case LobbyPlayer.Status.CANNOT_JOIN_FULL -> Strings.format(StringConstants.MU_X_CANNOT_JOIN_FULL, who); + case LobbyPlayer.Status.CANNOT_JOIN_IN_PROGRESS -> Strings.format(StringConstants.MU_X_CANNOT_JOIN_IN_PROGRESS, who); + case LobbyPlayer.Status.DECLINED_INVITE -> Strings.format(StringConstants.MU_X_DECLINED_INVITE, who); + case LobbyPlayer.Status.WITHDREW_REQUEST -> Strings.format(StringConstants.MU_X_WITHDREW_REQUEST, who); + case LobbyPlayer.Status.KICKED -> Strings.format(StringConstants.MU_X_REMOVED, who); + case LobbyPlayer.Status.DROPPED_OUT -> Strings.format(StringConstants.MU_X_DROPPED_OUT, who); + default -> null; + }; + } + + private static void tickLobbyRoomPlayersTable(final int var0, final ScrollPane var2, final boolean var3) { + final int requiredRating = 0; + final int requiredRatedGames = 0; + final int requiredUnlockedOptions = 0; + + final boolean var31 = var2.processScrollInput(var3, var2 == currentContextMenuParent, Component.LABEL_HEIGHT * 2 + 4, 4 * (2 + Component.LABEL_HEIGHT) * var0); + final List var32 = var2.content.children; + LobbyPlayer var33 = null; + + for (final LobbyPlayer player : var32) { + boolean var13 = false; + if (player.children == null) { + player._Ab = new Component<>(Component.UNSELECTED_LABEL_DARK_2); + player.addChild(player._Ab); + player._Ob = new Component<>(Component.UNSELECTED_LABEL_DARK_1); + player.addChild(player._Ob); + + player._Ob.textAlignment = Font.HorizontalAlignment.RIGHT; + player._xb = new Component<>(Component.LABEL); + player.addChild(player._xb); + player.recursivelySet_H(); + player._Jb = new Component<>(Component.GREEN_BUTTON); + player.addChild(player._Jb); + player._Mb = new Component<>(Component.RED_BUTTON); + var13 = true; + player.addChild(player._Mb); + } + + player._Ab.label = null; + final Component var14 = player._Ab; + player._Ab.height = 0; + player._Ob.label = null; + var14.width = 0; + final Component var15 = player._Ob; + player._Ob.height = 0; + var15.width = 0; + player._Jb.label = null; + player._Jb.height = 0; + final Component var16 = player._Jb; + player._Mb.label = null; + var16.width = 0; + player._Mb.height = 0; + final Component var17 = player._Mb; + player._xb.label = null; + var17.width = 0; + final Component var18 = player._xb; + player._xb.height = 0; + var18.width = 0; + player.width = var2.content.width; + int var19 = 0; + String var20 = player.playerDisplayName; + int var21 = 72; + if (var2 == Component.INVITE_PLAYER_LIST_SCROLL_PANE) { + var21 += 42; + } + + var20 = player._Ab.font.truncateWithEllipsisToFit(var20, var21); + assert var20 != null; + final boolean wasTruncated = !var20.equals(player.playerDisplayName); + if (player.crown >= 4) { + var20 = "" + var20; + } else if (player.crown > 0) { + var20 = "" + var20; + } + + player._Ab.label = var20; + int var24; + if (player.isInMap()) { + int var23 = 0xffcc66; + var24 = Drawing.WHITE; + if (player.rating < requiredRating || player.ratedGameCount < requiredRatedGames || (~player.unlockedOptionsBitmap & requiredUnlockedOptions) > 0) { + var23 = 0x806633; + var24 = 0x808080; + } + + player._Ab.textColor = player._Ob.textColor = player._Jb.textColor = var23; + player._Ab.mouseOverTextColor = player._Ab._qb = player._Ab._ab = var24; + player._Ob.mouseOverTextColor = player._Ob._qb = player._Ob._ab = var24; + player._Jb.mouseOverTextColor = player._Jb._qb = player._Jb._ab = var24; + if (Component.JOINED_PLAYERS_TABLE == var2) { + if (!unratedLobbyRoom.hasStarted) { + player._Mb.label = StringConstants.KICK; + } + } else if (player.inviteSent) { + player._Ab.label = Strings.format(StringConstants.INVITING_X, var20); + player._Mb.label = StringConstants.CANCEL; + } else if (player.joinRequestReceived) { + player._Ab.label = Strings.format(StringConstants.X_WANTS_TO_JOIN, var20); + player._Jb.label = StringConstants.ACCEPT; + player._Mb.label = StringConstants.REJECT; + } else { + player._Jb.label = StringConstants.INVITE; + } + + int var25 = 0; + if (unratedLobbyRoom != null && isCurrentRoomOwner() && localPlayerId != player.playerId) { + int var26; + if (player._Jb.label != null) { + var26 = player._Jb.e474() + 2 * _tga; + player._Jb.setBounds(var25, var19, var26, Component.LABEL_HEIGHT); + var25 += var26; + } + + if (player._Mb.label != null) { + if (var2 == Component.JOINED_PLAYERS_TABLE) { + var26 = 40; + } else { + var26 = player._Mb.e474() + _tga * 2; + } + + player._Mb.setBounds(var25, var19, var26, Component.LABEL_HEIGHT); + var25 += var26; + } + } + + player._Ab.setBounds(var25, var19, -var25 + (player.width - (42)), Component.LABEL_HEIGHT); + player._Ob.label = Integer.toString(player.rating); + player._Ob.setBounds(player.width - 40, var19, 40, Component.LABEL_HEIGHT); + if (player._Ab.isMouseOverTarget && wasTruncated) { + ClientLobbyRoom.currentTooltip = player.playerDisplayName; + } + + var19 += Component.LABEL_HEIGHT; + } + + final String var34 = playerRemovalReasonMessage(player.status, var20); + if (var34 != null) { + var24 = player._xb.font.breakLines(var34, player.width - _tga - _tga); + player._xb.label = var34; + player._xb._I = 256 * player.statusTimer / STATUS_MESSAGE_TIMEOUT_DURATION; + player._xb.setBounds(_tga, var19, -(2 * _tga) + player.width, var24 * Component.LABEL_HEIGHT); + var19 += Component.LABEL_HEIGHT * var24; + } + + if (!var31) { + player._gb = var19 - player.height; + } + + if (var13) { + var2.content.placeAfter(var33, player); + } + + if (player.clickButton != MouseState.Button.NONE && player.isInMap()) { + if (player._Jb.clickButton == MouseState.Button.NONE) { + if (player._Mb.clickButton == MouseState.Button.NONE) { + a641tvc(player, var2, mousePressX, mousePressY); + } else { + C2SPacket.kickFromGame(player.playerId); + } + } else { + C2SPacket.inviteToGame(player.playerId); + } + } + + if (player.isMouseOver && player.isInMap()) { + String message = null; + if (player.playerId == localPlayerId) { + if (player.ratedGameCount < requiredRatedGames) { + final int additionalRequiredRatedGames = requiredRatedGames - player.ratedGameCount; + message = Strings.format(StringConstants.GAMEOPT_YOU_NEED_RATED_GAMES, null, Integer.toString(additionalRequiredRatedGames)); + } else if (player.rating < requiredRating) { + message = Strings.format(StringConstants.GAMEOPT_YOU_NEED_RATING, null, Integer.toString(requiredRating)); + } else if ((requiredUnlockedOptions & ~player.unlockedOptionsBitmap) != 0) { + message = StringConstants.GAMEOPT_YOU_HAVENT_UNLOCKED; + } + } else if (player.ratedGameCount < requiredRatedGames) { + final int additionalRequiredRatedGames = requiredRatedGames - player.ratedGameCount; + if (additionalRequiredRatedGames == 1) { + message = Strings.format(StringConstants.GAMEOPT_PLAYER_NEEDS_1_RATED_GAME, var20); + } else { + message = Strings.format(StringConstants.GAMEOPT_PLAYER_NEEDS_RATED_GAMES, var20, Integer.toString(additionalRequiredRatedGames)); + } + } else if (player.rating < requiredRating) { + message = Strings.format(StringConstants.GAMEOPT_PLAYER_NEEDS_RATING, var20, Integer.toString(requiredRating)); + } else if ((requiredUnlockedOptions & ~player.unlockedOptionsBitmap) != 0) { + message = Strings.format(StringConstants.GAMEOPT_PLAYER_HASNT_UNLOCKED, var20); + } + + if (message != null) { + message = "" + message; + + if (Component.JOINED_PLAYERS_TABLE == var2 && isCurrentRoomOwner()) { + message = message + "
" + Strings.format(StringConstants.GAMEOPT_TRY_CHANGING_1); + } else { + message = message + "
" + Strings.format(StringConstants.GAMEOPT_NEED_CHANGING_1); + } + + if (Component.JOINED_PLAYERS_TABLE == var2 && !isCurrentRoomOwner()) { + final String var37 = unratedLobbyRoom.ownerName; + message = message + "
" + Strings.format(StringConstants.GAMEOPT_MIGHT_CHANGE, var37); + } + + ClientLobbyRoom.currentTooltip = message; + } + } + + var33 = player; + } + + } + + private static void tickRatedLobbyRoom(final boolean mouseNotYetHandled, final boolean inGame) { + layoutLobbyRoomPanels(ratedLobbyRoomTransitionCounter); + + if (ratedLobbyRoom != null) { + final Component var4 = Component.INVITE_PLAYERS_BUTTON; + Component.INVITE_PLAYERS_BUTTON.height = 0; + var4.width = 0; + final Component var5 = Component.FIND_OPPONENTS_BUTTON; + Component.FIND_OPPONENTS_BUTTON.height = 0; + var5.width = 0; + final Component var6 = Component.WAITING_TO_START_LABEL; + Component.WAITING_TO_START_LABEL.height = 0; + var6.width = 0; + Component.GAME_OWNER_HEADING.label = StringConstants.RATED_GAME.toUpperCase(); + final int var7 = (2 + Component.GAME_INFO_CONTAINER.width) / 2; + Component.WAITING_TO_START_LABEL.setBounds(0, Component.GAME_INFO_CONTAINER.height - 40, var7 - 2, 40); + Component.FIND_OPPONENTS_BUTTON.setBounds(var7, Component.GAME_INFO_CONTAINER.height - 40, -var7 + Component.GAME_INFO_CONTAINER.width, 40); + boolean var8; + int var9; + int var10; + var8 = false; + var9 = 0; + + for (var10 = 0; var10 < NUM_PLAYERS_OPTION_VALUES.length; ++var10) { + final boolean var11 = (playerSeatsFilledBitmap[var10 / 8] & 1 << (var10 & 7)) != 0; + if (var11) { + ++var9; + } + + if (var11 && NUM_PLAYERS_OPTION_VALUES[var10] != 2) { + var8 = true; + break; + } + } + + if (var9 == 0) { + var8 = true; + } + + Component.FIND_OPPONENTS_BUTTON.enabled = true; + String var12; + if (justRecievedRoomDetailsFromServer) { + Component.RETURN_TO_LOBBY_BUTTON.enabled = false; + Component.RATED_GAME_TIPS_LABEL.label = StringConstants.RATED_GAME_TIPS; + var12 = var8 ? StringConstants.SEARCHING_FOR_OPPONENTS : StringConstants.SEARCHING_FOR_OPPONENT; + var10 = Component.WAITING_TO_START_LABEL.font.measureLineWidth(var12) + 3 * Component.WAITING_TO_START_LABEL.font.getAdvanceWidth('.'); + Component.WAITING_TO_START_LABEL._kb = (-var10 + Component.WAITING_TO_START_LABEL.width) / 2; + if ((_ssw & 48) == 16) { + var12 = var12 + "."; + } + + Component.WAITING_TO_START_LABEL.textAlignment = Font.HorizontalAlignment.LEFT; + if ((_ssw & 48) == 32) { + var12 = var12 + ".."; + } + + if ((_ssw & 48) == 48) { + var12 = var12 + "..."; + } + + Component.WAITING_TO_START_LABEL.label = var12; + Component.FIND_OPPONENTS_BUTTON.label = StringConstants.CANCEL.toUpperCase(); + } else { + Component.FIND_OPPONENTS_BUTTON.label = (!var8 ? StringConstants.FIND_OPPONENT_SINGULAR : StringConstants.FIND_OPPONENTS).toUpperCase(); + Component.RATED_GAME_TIPS_LABEL.label = Strings.format(!var8 ? StringConstants.RATED_GAME_TIPS_SETUP_SINGULAR : StringConstants.INFO_RATED_GAME, Component.FIND_OPPONENTS_BUTTON.label); + Component.WAITING_TO_START_LABEL.label = StringConstants.WAITING_TO_START_HINT; + Component.RETURN_TO_LOBBY_BUTTON.enabled = true; + _wgd = true; + if (_peD != null) { + _wgd = false; + _sbh = false; + if (_lrc == null) { + _lrc = new byte[GAMEOPT_CHOICES_COUNTS.length]; + _ekF = new boolean[GAMEOPT_CHOICES_COUNTS.length]; + } + + for (var9 = 0; var9 < GAMEOPT_CHOICES_COUNTS.length; ++var9) { + _ekF[var9] = false; + } + + a068js(-1, GAMEOPT_CHOICES_COUNTS.length, 0, true, -1, -1); + if (adminLevel >= 2 && keysDown[12]) { + _wgd = true; + } + } + + if (!_wgd) { + Component.FIND_OPPONENTS_BUTTON.enabled = false; + if (Component.FIND_OPPONENTS_BUTTON.isMouseOver) { + var12 = null; + if (_sbh) { + var12 = "" + StringConstants.MU_OPTIONS_PLAYERS + ""; + } + + for (var10 = 0; GAMEOPT_CHOICES_COUNTS.length > var10; ++var10) { + if (_ekF[var10]) { + final String var13 = "" + StringConstants.GAMEOPT_LABELS[var10] + ""; + if (var12 == null) { + var12 = var13; + } else { + var12 = var12 + ", " + var13; + } + } + } + + ClientLobbyRoom.currentTooltip = "" + StringConstants.GAMEOPT_NO_VALID_COMBOS + "
" + StringConstants.GAMEOPT_PLEASE_TRY_CHANGING + var12; + } + } + } + } + + lobbyRoomLeftPanel.rootProcessMouseEvents(mouseNotYetHandled && !inGame && !invitePlayersDialogOpen); + Component.GAME_INFO_CONTAINER.rootProcessMouseEvents(mouseNotYetHandled && !inGame && !invitePlayersDialogOpen); + invitePlayersDialog.rootProcessMouseEvents(mouseNotYetHandled && !inGame && invitePlayersDialogOpen); + lobbyRoomTabbedPlayerList.view.f487(); + if (ratedLobbyRoom != null) { + if (Component.RETURN_TO_LOBBY_BUTTON.clickButton != MouseState.Button.NONE) { + C2SPacket.returnToLobby(); + } + + if (Component.FIND_OPPONENTS_BUTTON.clickButton != MouseState.Button.NONE) { + if (justRecievedRoomDetailsFromServer) { + C2SPacket.acknowledgeRatedRoomInfo(); + } else { + C2SPacket.updateRatedGamePreferences(playerSeatsFilledBitmap, maxAiPlayersSelection, allowSpectateSelection, gameoptChoicesBitmap); + } + } + + a626sc(true, ratedLobbyRoom); + } + } + + private static boolean tickPopups(boolean mouseNotYetHandled) { + if (isPopupOpen()) { + tickQuickChat(mouseNotYetHandled); + if (ContextMenu.openInstance != null && ContextMenu.openInstance.tick(mouseNotYetHandled)) { + dismissContextMenu(); + mouseNotYetHandled = false; + } + + AddOrRemovePlayerPopup.tick(mouseNotYetHandled); + ReportAbuseDialog.tick(mouseNotYetHandled); + mouseNotYetHandled = false; + } + + return mouseNotYetHandled; + } + + private static void b150af() { + g150fp(); + i150ak(); + } + + private static void g150fp() { + if (_pgJ > 0) { + --_pgJ; + } + + if (_dmgm != JagexBaseApplet.screenBuffer.height) { + _flf += -_dmgm + JagexBaseApplet.screenBuffer.height; + _dmgm = JagexBaseApplet.screenBuffer.height; + } + + if (_pgJ > 0) { + a150bq(); + } + + } + + public static void a150bq() { + final int var0 = 400; + final int var1 = var0 - _pgJ * _pgJ; + final int var3 = _flf + var1 * (_dmgm - _flf) / var0; + Component._tgc.setBounds(_tmh, var3, SCREEN_WIDTH, 120); + a370qc(_dmgm - 24, _tga, ClientLobbyRoom._qob); + } + + private static boolean processChatKeyInput() { + if (QuickChatHelpPanel.openInstance != null && lastTypedKeyCode == KeyState.Code.ESCAPE) { + QuickChatHelpPanel.openInstance = null; + return true; + } else if (isChatboxSelected) { + if (canOnlyQuickChat) { + return false; + } else { + boolean consumed = processChatKeyboardInput(); + if (lastTypedKeyCode == KeyState.Code.TAB || lastTypedKeyCode == KeyState.Code.ENTER) { + consumed = true; + isChatboxSelected = false; + } + + if (lastTypedKeyCode == KeyState.Code.ESCAPE) { + discardTypedChatMessage(); + consumed = true; + isChatboxSelected = false; + } + + return consumed; + } + } else if (isQuickChatOpen || lastTypedKeyCode == KeyState.Code.F9 || lastTypedKeyCode == KeyState.Code.F10 || lastTypedKeyCode == KeyState.Code.F11) { + return processQuickChatKeyInput(); + } else if (lastTypedKeyCode == KeyState.Code.TAB && !canOnlyQuickChat) { + isChatboxSelected = true; + return true; + } else { + return false; + } + } + + private static void loadJpegImages(final ResourceLoader loader) { + STAR_FIELD = loadJpgSprite(loader, "starfield"); + WIN_SPRITE = loadJpgSprite(loader, "win"); + LOSE_SPRITE = loadJpgSprite(loader, "lose"); + } + + private static void a813qr(final boolean var0) { + a540ta(var0); + a877im(var0); + a430mj(var0); + } + + private static void a877im(boolean var0) { + if (isPopupOpen()) { + var0 = false; + } + + GameUI.a893(var0); + b150lc(); + } + + private static void a174ca(final ResourceLoader var1, final ResourceLoader var2, final ResourceLoader spriteLoader) { + final String[] gameoptSpritesItems = {null, "turntime_icons", "game_icons", "galaxysize_icons", "type_icons"}; + final Sprite[][] gameoptSprites = new Sprite[gameoptSpritesItems.length][]; + ClientLobbyRoom.GAMEOPT_SPRITES = gameoptSprites; + + for (int i = 0; i < gameoptSpritesItems.length; ++i) { + if (gameoptSpritesItems[i] != null) { + gameoptSprites[i] = SpriteResource.loadSprites(spriteLoader, "", gameoptSpritesItems[i]); + } + } + + StringConstants.MU_OPTIONS_PLAYERS = StringConstants.TEXT_HUMAN_PLAYERS; + Component.a469(var1, var2, gameoptSprites); + LOBBY_ICON = SpriteResource.loadSprite(spriteLoader, "", "lobbyicon"); + _hmo = false; + _peD = _msc; + _imb = new int[3]; + chatMessages = new ChatMessage[3000]; + chatMessageCount = 0; + _kpi = 200; + } + + private static void a778cf(final boolean var2) { + final String var6; + if (currentChatChannel == Channel.PRIVATE) { + var6 = StringConstants.SEND_PM; + } else { + var6 = StringConstants.MESSAGE_GAME; + } + + a500er(var6, var2, Component._rcl); + } + + private static void a500er(final String var2, final boolean var4, final int var6) { + if (Component._taio.clickButton != MouseState.Button.NONE && !cannotChat) { + if (JagexApplet.canOnlyQuickChat) { + ContextMenu.sendChannelMessageQC(); + } else { + isChatboxSelected = true; + } + } + + if (isChatboxSelected) { + a411ca(var2, var6); + _faX.rootProcessMouseEvents(var4); + if (var4) { + if (HIDE_CHAT_TEMPORARILY_LABEL.clickButton != MouseState.Button.NONE) { + isChatboxSelected = false; + } + + if (_cbl.clickButton != MouseState.Button.NONE) { + discardTypedChatMessage(); + isChatboxSelected = false; + } + } + } + + } + + private static void a411ca(final String var3, final int var4) { + _mbn.label = var3; + if (currentChatChannel == Channel.PRIVATE) { + _cbl.label = ReportAbuseDialog._Kb; + } else { + _cbl.label = StringConstants.ESC_CANCEL_THIS_LINE; + } + + final short var9 = 495; + final byte var10 = 5; + _abAb.setBounds(5, var10, 485, Component.LABEL_HEIGHT); + chatMessageLabel.setBounds(0, 0, -Component._cgC.width + _abAb.width, Component.LABEL_HEIGHT); + Component._cgC.setBounds(chatMessageLabel.width, 0, Component._cgC.width, Component.LABEL_HEIGHT); + final int var13 = var10 + Component.LABEL_HEIGHT + var4; + HIDE_CHAT_TEMPORARILY_LABEL.setBounds(5, var13, HIDE_CHAT_TEMPORARILY_LABEL.e474(), Component.LABEL_HEIGHT); + final int var11 = _cbl.e474(); + _cbl.setBounds(-var11 + (490), var13, var11, Component.LABEL_HEIGHT); + int var12 = 5 + var13 + Component.LABEL_HEIGHT; + _mbn.setBounds(0, 0, var9, 20); + _few.setBounds(0, 20, var9, var12); + _few.nineSliceSprites = Component.createGradientOutlineSprites(_few.height, 11579568, 8421504, 2105376); + var12 += 20; + _faX.setBounds(73, -(var12 / 2) + 180, var9, var12); + } + + private static void a111ph() { + if (cannotChat) { + DobToEnableChatForm.instance.keyTyped(lastTypedKeyCode, lastTypedKeyChar); + } else if (isQuickChatOpen) { + processQuickChatKeyInput(); + } else if (!a330ms() && !JagexApplet.canOnlyQuickChat) { + processChatKeyboardInput(); + } + } + + private static boolean a330ms() { + final boolean var3 = ratedLobbyRoom != null; + if (lastTypedKeyCode == KeyState.Code.F9 && TutorialAI2.a051(JagexApplet._uof, _cvco, _D, _bqe)) { + return (_D == Channel.PRIVATE || !var3) && ContextMenu.autoRespond(_bqe, _cvco, JagexApplet._uof, _D); + } else if (lastTypedKeyCode != KeyState.Code.F10) { + if (lastTypedKeyCode == KeyState.Code.F11 && _cvcn) { + if (_tlr == Channel.PRIVATE && !a788(vm_._aco, vm_._ahS)) { + return false; + } else if (_tlr != Channel.PRIVATE && var3) { + return false; + } else { + if (b154chmr()) { + C2SPacket.sendQuickChatMessage(_tlr, vm_._ahS, _vsd); + } + + return true; + } + } else { + return false; + } + } else if (var3) { + return false; + } else { + ContextMenu.sendChannelMessageQC(); + return true; + } + } + + private static Sprite[] generateButtonSlices() { + final Sprite[] slices = new Sprite[]{new Sprite(10, 10), new Sprite(10, 10), new Sprite(10, 10), new Sprite(10, 10), null, new Sprite(10, 10), new Sprite(10, 10), new Sprite(10, 10), new Sprite(10, 10)}; + Drawing.saveContext(); + slices[0].installForDrawing(); + final int color = 0x3ca4a7; + a229ch(color, 10, 30, 0, 0, color, 30); + slices[1].installForDrawing(); + a229ch(color, 10, 30, -10, 0, color, 30); + slices[2].installForDrawing(); + a229ch(color, 10, 30, -20, 0, color, 30); + slices[3].installForDrawing(); + a229ch(color, 10, 30, 0, -10, color, 30); + slices[5].installForDrawing(); + a229ch(color, 10, 30, -20, -10, color, 30); + slices[6].installForDrawing(); + a229ch(color, 10, 30, 0, -21, color, 30); + slices[7].installForDrawing(); + a229ch(color, 10, 30, -10, -22, color, 30); + slices[8].installForDrawing(); + a229ch(color, 10, 30, -20, -21, color, 30); + Drawing.restoreContext(); + return slices; + } + + public static void a229ch(final int color1, final int var2, final int var3, final int var4, final int var5, final int color2, final int var7) { + if (var2 * 2 <= var3) { + final int[] bounds = new int[4]; + Drawing.saveBoundsTo(bounds); + Drawing.horizontalLine(var2 + var4, var5, var3 - 2 * var2, color1); + Drawing.horizontalLine(var2 + var4, var5 + var7, var3 - (2 * var2), color2); + Drawing.expandBoundsToInclude(var4, var5, var4 + var2, var5 + var2); + Drawing.strokeCircle(var2 + var4, var5 + var2, var2, color1); + Drawing.restoreBoundsFrom(bounds); + Drawing.expandBoundsToInclude(var4 + (var3 - var2), var5, var4 + var3, var5 + var2); + Drawing.strokeCircle(var3 - var2 + (var4 - 1), var5 + var2, var2, color1); + Drawing.restoreBoundsFrom(bounds); + Drawing.expandBoundsToInclude(var4, var7 - var2 + var5, var4 + var2, var5 + var7); + Drawing.strokeCircle(var4 + var2, var7 + var5 - var2 - 1, var2, color2); + Drawing.restoreBoundsFrom(bounds); + Drawing.expandBoundsToInclude(-var2 + var3 + var4, var5 + var7 - var2, var4 + var3, var5 + var7); + Drawing.strokeCircle(var4 - 1 - (var2 - var3), var7 + var5 - (var2 + 1), var2, color2); + Drawing.restoreBoundsFrom(bounds); + + for (int i = 0; i < var7 - 20; ++i) { + final int color3 = Drawing.alphaOver(color2, color1, 256 * i / (var7 - 20)); + Drawing.setPixel(var4, var2 + var5 + i, color3); + Drawing.setPixel(var3 + var4 - 1, i + var5 + var2, color3); + } + } + } + + private static boolean recieveS2cPacket() { + if (loginState == LoginState.LOGGED_IN) { + if (nextS2cPacketType < 0) { + s2cPacket.pos = 0; + if (!JagexApplet.s2cBytesAvailable(1)) { + return false; + } + + nextS2cPacketType = s2cPacket.readCipheredByte(); + s2cPacket.pos = 0; + nextS2cPacketLen = S2CPacket.LENGTH[nextS2cPacketType]; + } + + if (!JagexApplet.isS2cPacketFullyRecieved()) { + return false; + } + + thirdPreviousS2cPacketType = secondPreviousS2cPacketType; + secondPreviousS2cPacketType = previousS2cPacketType; + previousS2cPacketType = currentS2cPacketType; + currentS2cPacketType = nextS2cPacketType; + nextS2cPacketType = -1; + return true; + } else { + return false; + } + } + + private static @Nullable Menu.DialogOption d474cq() { + boolean var1 = false; + boolean var2 = false; + + while (nextTypedKey()) { + Menu._gsl.processKeyInputVertical(); + if (Menu._gsl.isItemActive()) { + var1 = true; + } + + if (lastTypedKeyCode == KeyState.Code.ESCAPE) { + var2 = true; + } + } + + Menu._gsl.processMouseInput(Menu.a313gui(mouseX, mouseY), Menu.a313gui(mousePressX, mousePressY)); + if (Menu._gsl.isItemActive()) { + var1 = true; + } + + Menu.DialogOption var3 = null; + if (var1 && Menu._gsl.selectedItem >= 0) { + var3 = Menu._E[Menu._gsl.selectedItem]; + if (var3 == Menu.DialogOption.ACCEPT || var3 == Menu.DialogOption.CLOSE) { + b423jf(); + } + } else if (var2 && Menu.currentFullscreenDialog != Menu.FullscreenDialog.ACCEPT_COUNTDOWN) { + b423jf(); + } + + if (var3 == null && Menu.currentFullscreenDialog == Menu.FullscreenDialog.ACCEPT_COUNTDOWN) { + final long var4 = PseudoMonotonicClock.currentTimeMillis() - Menu._brp; + final int var6 = (int) ((10999L - var4) / 1000L); + if (var6 <= 0) { + var3 = Menu.DialogOption.ACCEPT; + Menu.showFullscreenDialog(Menu.FullscreenDialog.TIMEOUT, true); + } + } + + return var3; + } + + private static boolean isProfileInitialized() { + return (areAchievementsInitialized && loadedProfile) || isAnonymous; + } + + private static boolean f427kh() { + JagexApplet._vmNb = true; + _ipb = PseudoMonotonicClock.currentTimeMillis() + 15000L; + return connectionState == ConnectionState.RECONNECTING; + } + + private static void a778cc(final boolean mouseNotYetHandled, final int mouseWheelRotation) { + if (_pgJ < 20) { + ++_pgJ; + } + + if (_dmgm != JagexBaseApplet.screenBuffer.height) { + _flf += JagexBaseApplet.screenBuffer.height - _dmgm; + _dmgm = JagexBaseApplet.screenBuffer.height; + } + + if (_pgJ > 0) { + a150bq(); + Component._tgc.rootProcessMouseEvents(mouseNotYetHandled); + if (DobToEnableChatForm.instance != null) { + if (cannotChat) { + DobToEnableChatForm.instance.tickRoot(Component._tgc.x2, Component._tgc.y2, mouseNotYetHandled); + } else { + DobToEnableChatForm.instance = null; + } + } + + for (final Channel channel : Channel.values()) { + final int i = channel.ordinal(); + final Component var5 = Component.chatFilterButtons[i]; + if (var5 != null) { + if (var5.clickButton != MouseState.Button.NONE) { + a939tai3(channel, var5); + } + + final ChatMessage.FilterLevel var6 = ContextMenu.getChatChannelFilter(channel); + Component.chatFilterIcons[i].sprite = Component.CHAT_FILTER_SPRITES[var6.ordinal()]; + Component.chatFilterLabels[i].label = Component.CHAT_FILTER_LABELS[var6.ordinal()]; + } + } + + if (Component._a.clickButton != MouseState.Button.NONE) { + ReportAbuseDialog.openInstance = new ReportAbuseDialog(Component._a.x2, Component._a.y2, Component._a.width, Component._a.height, Component.TAB_ACTIVE, Component.CLOSE_BUTTON, Component.LABEL, Component.CHECKBOX, Component.UNSELECTED_LABEL, null, 0L); + } + + final ChatMessage var7 = a249chmr(mouseWheelRotation, _tga); + if (var7 != null) { + a681ks(var7); + } + + final String var8 = b738bk(); + if (var8 != null) { + ClientLobbyRoom.currentTooltip = var8; + } + } + } + + private static String b738bk() { + String var0 = null; + String var1 = null; + if (currentChatChannel == Channel.LOBBY && ratedLobbyRoom != null) { + var1 = StringConstants.PUBLIC_CHAT_UNAVAILABLE_RATED_GAME; + } + + if (currentChatChannel == Channel.PRIVATE && !a788(ContextMenu.recipientPlayerId, ContextMenu.normalizedRecipientPlayerName)) { + if (a988da(ContextMenu.normalizedRecipientPlayerName)) { + var1 = Strings.format(StringConstants.PRIVATE_CHAT_FRIEND_OFFLINE, ContextMenu.recipientPlayerName); + } else { + var1 = Strings.format(StringConstants.PRIVATE_CHAT_FRIEND_NOT_LISTED, ContextMenu.recipientPlayerName); + } + + if (isQuickChatOpen) { + ContextMenu.showChatMessage(Channel.PRIVATE, var1, 0, null, null); + closeQuickChatIfOpen(); + } + } + + if (var1 == null && !_K && _faX == null) { + var1 = StringConstants.CHAT_VIEW_SCROLLED_UP; + } + + if (var1 == null) { + String var3 = playerDisplayName; + var3 = a803(var3); + String prefix = ""; + String var5 = "|"; + Channel channel = currentChatChannel; + int var7 = 0; + final String var8; + if (channel == Channel.PRIVATE) { + prefix = Strings.format(StringConstants.PRIVATE_QUICK_CHAT_TO_X, ContextMenu.recipientPlayerName); + var8 = Strings.format(StringConstants.PRIVATE_QUICK_CHAT_FROM_X, var3); + var7 = chatMessageLabel.width - 485 - (-Component._cgC.width - Component.CHAT_FONT.measureLineWidth(var8) + Component.CHAT_FONT.measureLineWidth(prefix)); + if (var7 < 0) { + var7 = 0; + } + } else { + if (channel == Channel.LOBBY) { + if (unratedLobbyRoom == null) { + prefix = "[" + StringConstants.MU_CHAT_LOBBY + "] "; + } + + if (unratedLobbyRoom != null) { + channel = Channel.ROOM; + prefix = "[" + Strings.format(StringConstants.XS_GAME, unratedLobbyRoom.ownerName) + "] "; + } + } + + var8 = !a427cel() ? ": " : ": "; + prefix = prefix + var3 + var8; + if (cannotChat) { + var5 = ""; + prefix = "" + prefix + StringConstants.DOB_CHAT_DISABLED + ""; + } else if (JagexApplet.canOnlyQuickChat) { + var5 = ""; + prefix = "" + prefix + StringConstants.CLICK_TO_QUICKCHAT + ""; + } + + final int var9 = Component.CHAT_FONT.measureLineWidth(prefix); + if (!a427cel()) { + if (chatMessageLabel.isMouseOverTarget && var9 > -chatMessageLabel.x2 + mouseX) { + if (cannotChat) { + var0 = "Broken!"; + } else { + var0 = StringConstants.CLICK_TO_QUICKCHAT; + } + } + + if (chatMessageLabel.clickButton != MouseState.Button.NONE && chatMessageLabel.relativeClickX < var9 && !cannotChat) { + ContextMenu.sendChannelMessageQC(); + } + } + } + + a790cq(Component.CHANNEL_TEXT_COLORS_1[channel.ordinal()], var5, prefix + Font.escapeTags(typedChatMessage.toString()), var7); + if (!isChatboxSelected) { + Component._cgC.isMouseOverTarget = false; + } + + if (Component._cgC.isMouseOverTarget) { + var0 = Strings.format(StringConstants.PRIVATE_CHAT_BLANK_AREA_EXPLANATION, var3, ContextMenu.recipientPlayerName); + } + } else { + a790cq(_hoc, null, var1, 0); + } + + return var0; + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + private static boolean a427cel() { + return _cka != null; + } + + public static boolean a988da(final String var1) { + return PlayerListEntry.lookupFriend(var1) != null; + } + + private static void a423ppi() { + dismissContextMenu(); + AddOrRemovePlayerPopup.openInstance = null; + ReportAbuseDialog.openInstance = null; + closeQuickChat(); + } + + public static void a034so(int var1, int var2, final Sprite var3) { + int var4 = var1 + Drawing.width * var2; + int var5 = 0; + int var6 = var3.height; + int var7 = var3.width; + int var8 = -var7 + Drawing.width; + int var9 = 0; + int var10; + if (Drawing.top > var2) { + var10 = Drawing.top - var2; + var6 -= var10; + var2 = Drawing.top; + var5 = var10 * var7; + var4 += Drawing.width * var10; + } + + if (var1 < Drawing.left) { + var10 = -var1 + Drawing.left; + var5 += var10; + var9 += var10; + var8 += var10; + var4 += var10; + var7 -= var10; + var1 = Drawing.left; + } + + if (var6 + var2 > Drawing.bottom) { + var6 -= var2 - (-var6 + Drawing.bottom); + } + + if (Drawing.right < var1 + var7) { + var10 = -Drawing.right + var1 + var7; + var7 -= var10; + var9 += var10; + var8 += var10; + } + + if (var7 > 0 && var6 > 0) { + a699ge(var3.pixels, var5, Drawing.screenBuffer, var7, var4, var9, var6, var8); + } + } + + private static void a699ge(final int[] var0, int var1, final int[] var2, final int var5, int var6, final int var7, final int var8, final int var9) { + for (int var12 = -var8; var12 < 0; ++var12) { + for (int var13 = -var5; var13 < 0; ++var13) { + final int var3 = var0[var1++]; + if (var3 == 0 || var3 == 255) { + ++var6; + } else { + final int var11 = 255 & var3; + final int var10 = var2[var6]; + var2[var6++] = 16711935 & (16711935 & var10) * var11 >> 8 | (16711920 & (var10 & 65280) * var11) >> 8; + } + } + + var1 += var7; + var6 += var9; + } + } + + private static void a423kd() { + int var0 = Menu._uqk; + int var1 = 0; + if (Menu.currentFullscreenDialog == Menu.FullscreenDialog.ACCEPT_COUNTDOWN) { + final long var2 = PseudoMonotonicClock.currentTimeMillis() - Menu._brp; + var1 = (int) ((10999L - var2) / 1000L); + if (var1 < 0) { + var1 = 0; + } + } + + for (int var9 = 0; var9 < Menu._tuef.length; ++var9) { + final int var3 = Menu._ssa[var9]; + final int var4; + if (var3 < 0) { + var4 = 0x258488; + } else if (Menu._gsl.selectedItem == var3) { + var4 = 0x2ad0d6; + } else { + var4 = 0x258488; + } + + String var5 = Menu._tuef[var9]; + int var6; + int var7; + if (Menu.currentFullscreenDialog == Menu.FullscreenDialog.ACCEPT_COUNTDOWN && var1 == 1) { + var6 = Math.max(Menu._kpo.length, Menu._nld.length); + var7 = Math.max(Menu._hmp.length, Menu._kdb.length); + if (var9 >= 6 && var9 < var6 + 6) { + var5 = Menu._kpo.length + var9 + (-6 - var6) >= 0 ? Menu._kpo[var9 - 6 - (-Menu._kpo.length + var6)] : ""; + } + + if (var6 + 7 <= var9 && var9 < var7 + 7 + var6) { + var5 = -var6 + (var9 - 7) >= Menu._kdb.length ? "" : Menu._kdb[var9 - var6 - 7]; + } + } + + if (var3 == -2) { + var5 = Integer.toString(var1); + } + + var6 = vm_.a827(var5); + var7 = -(var6 >> 1) + SCREEN_CENTER_X; + if (var3 >= 0) { + var0 += 2; + if (Menu.buttonSprite != null) { + Menu.buttonSprite.draw((8 << 1) + Menu.get_idb(), -8 + var7, var0, (8 << 1) + var6); + } + + var0 += 8; + } + + Menu.FONT.draw(var5, var7, Menu.FONT.capHeight + var0, var4); + if (var3 < 0) { + var0 += Menu.get_idb(); + } else { + var0 += Menu.get_idb() + 2 + 8; + } + } + } + + private static Sprite loadJpgSprite(final ResourceLoader loader, String key) { + if (!loader.hasResource("", key)) { + key = key + ".jpg"; + if (!loader.hasResource("", key)) { + return null; + } + } + + final byte[] imageData = loader.getResource("", key); + return new Sprite(imageData, fullScreenCanvas != null ? fullScreenCanvas : canvas); + } + + private static boolean processChatKeyboardInput() { + final boolean var3 = (_K || _faX != null) + && !(currentChatChannel == Channel.LOBBY && ratedLobbyRoom != null) + && !(currentChatChannel == Channel.PRIVATE && !a788(ContextMenu.recipientPlayerId, ContextMenu.normalizedRecipientPlayerName)); + + if (lastTypedKeyCode == KeyState.Code.ENTER) { + if (var3) { + if (typedChatMessage.length() > 0) { + final String message = typedChatMessage.toString(); + if (EmailLoginCredentials.containsPassword(message)) { + ContextMenu.showChatMessage(Channel.PRIVATE, StringConstants.DONT_TELL_PASSWORD, 0, null, null); + ContextMenu.showChatMessage(Channel.PRIVATE, StringConstants.PLEASE_CHANGE_PASSWORD, 0, null, null); + } else { + Channel channel = currentChatChannel; + if (channel == Channel.LOBBY && unratedLobbyRoom != null) { + channel = Channel.ROOM; + } + + if (ContextMenu.getChatChannelFilter(channel) == ChatMessage.FilterLevel.NONE) { + ContextMenu.setChatFilter(channel, ChatMessage.FilterLevel.FRIENDS); + } + + C2SPacket.sendChatMessage(currentChatChannel, ContextMenu.recipientPlayerName, message); + } + } + + discardTypedChatMessage(); + } else if (currentChatChannel != Channel.LOBBY) { + discardTypedChatMessage(); + } + return true; + } else if (lastTypedKeyCode == KeyState.Code.BACKSPACE) { + if (var3 && typedChatMessage.length() > 0) { + AddOrRemovePlayerPopup.removeLastCharacterFromStringBuilder(typedChatMessage); + } + return true; + } else if (isAcceptedChatKeyChar(lastTypedKeyChar)) { + final int var12; + if (var3 && typedChatMessage.length() < 80) { + typedChatMessage.append(lastTypedKeyChar); + final short var5 = 485; + String var6 = playerDisplayName; + var6 = a803(var6); + String var7; + if (currentChatChannel == Channel.PRIVATE) { + var7 = Strings.format(StringConstants.PRIVATE_QUICK_CHAT_TO_X, a034ih(ContextMenu.recipientPlayerName)); + final String var8 = Strings.format(StringConstants.PRIVATE_QUICK_CHAT_FROM_X, var6); + final int var9 = Component.CHAT_FONT.measureLineWidth(var7); + final int var10 = Component.CHAT_FONT.measureLineWidth(var8); + if (var9 <= var10) { + var12 = var5 - var10; + } else { + var12 = var5 - var9; + } + } else { + var7 = ""; + if (currentChatChannel == Channel.LOBBY) { + if (unratedLobbyRoom == null) { + var7 = "[" + StringConstants.MU_CHAT_LOBBY + "] "; + } + + if (unratedLobbyRoom != null) { + var7 = "[" + Strings.format(StringConstants.XS_GAME, unratedLobbyRoom.ownerName) + "] "; + } + } + + var7 = var7 + var6 + ": "; + var12 = var5 - Component.CHAT_FONT.measureLineWidth(var7); + } + + if (var12 < Component.CHAT_FONT.measureLineWidth(typedChatMessage.toString())) { + AddOrRemovePlayerPopup.removeLastCharacterFromStringBuilder(typedChatMessage); + } + } + + return true; + } else { + return false; + } + } + + private static boolean isAcceptedChatKeyChar(final char c) { + if (c >= ' ' && c <= '~') { + return true; + } else if (c >= 0xa0 && c <= 0xff) { + return true; + } else { + return c == 'Œ' || c == 'œ' || c == 'Ÿ' || c == Strings.EM_DASH || c == '€'; + } + } + + private static void b150nj() { + _faX = null; + if (_cka != null) { + Component._cgC = _erj; + chatMessageLabel = _cka; + chatMessageLabel.mouseOverTextColor = -1; + _erj = null; + chatMessageLabel._qb = -1; + _cka = null; + } + + _abAb = null; + HIDE_CHAT_TEMPORARILY_LABEL = null; + _mbn = null; + _cbl = null; + isChatboxSelected = true; + } + + private static void a939tai3(final @NotNull Channel channel, final Component target) { + showContextMenu(null, target, 0L, null, null, -1, channel); + + if (channel == Channel.LOBBY) { + ContextMenu.openInstance.view.addItem(Component.CHAT_FILTER_SPRITES[0], StringConstants.MU_CHAT_LOBBY_SHOW_ALL, ContextMenu.ClickAction.CHAT_SHOW_ALL); + ContextMenu.openInstance.view.addItem(Component.CHAT_FILTER_SPRITES[1], StringConstants.MU_CHAT_LOBBY_FRIENDS, ContextMenu.ClickAction.CHAT_SHOW_FRIENDS); + ContextMenu.openInstance.view.addItem(Component.CHAT_FILTER_SPRITES[2], StringConstants.MU_CHAT_LOBBY_HIDE, ContextMenu.ClickAction.CHAT_SHOW_NONE); + } else if (channel == Channel.ROOM) { + ContextMenu.openInstance.view.addItem(Component.CHAT_FILTER_SPRITES[0], StringConstants.MU_CHAT_GAME_SHOW_ALL, ContextMenu.ClickAction.CHAT_SHOW_ALL); + ContextMenu.openInstance.view.addItem(Component.CHAT_FILTER_SPRITES[1], StringConstants.MU_GAME_CHAT_FRIENDS, ContextMenu.ClickAction.CHAT_SHOW_FRIENDS); + ContextMenu.openInstance.view.addItem(Component.CHAT_FILTER_SPRITES[2], StringConstants.MU_CHAT_GAME_HIDE, ContextMenu.ClickAction.CHAT_SHOW_NONE); + } else if (channel == Channel.PRIVATE) { + ContextMenu.openInstance.view.addItem(Component.CHAT_FILTER_SPRITES[0], StringConstants.MU_CHAT_PM_SHOW_ALL, ContextMenu.ClickAction.CHAT_SHOW_ALL); + ContextMenu.openInstance.view.addItem(Component.CHAT_FILTER_SPRITES[1], StringConstants.MU_CHAT_PM_FRIENDS, ContextMenu.ClickAction.CHAT_SHOW_FRIENDS); + ContextMenu.openInstance.view.addItem(Component.CHAT_FILTER_SPRITES[2], StringConstants.MU_CHAT_INVISIBLE_AND_SILENT_MODE, ContextMenu.ClickAction.CHAT_SHOW_NONE); + } + + ContextMenu.openInstance.view.positionRelativeToTarget(target.x2, target.y2, target.width, target.height); + } + + public static void showContextMenu(final ScrollPane parent, + final Component target, + final long playerId, + final String playerName, + final String playerDisplayName, + final int roomId, + final @Nullable Channel channel) { + currentContextMenuParent = parent; + ContextMenu.openInstance = new ContextMenu(target, playerId, playerName, playerDisplayName, roomId, channel); + } + + private static PlayerListEntry tickFriendList(final boolean mouseStill, final int mouseWheelRotation) { + final boolean var3 = Component.FRIEND_LIST.scrollPane.processScrollInput( + mouseStill, currentContextMenuParent == Component.FRIEND_LIST.scrollPane, Component.LABEL_HEIGHT + 2, mouseWheelRotation * (Component.LABEL_HEIGHT + 2) * 3 + ); + + PlayerListEntry clickedEntry = null; + if (PlayerListEntry.serverStatus == PlayerListEntry.ServerStatus.LOADED) { + Component.FRIEND_LIST_PANEL.enabled = true; + Component.SERVER_INFO_LABEL.label = Strings.format(StringConstants.YOU_ARE_ON_X_SERVER, currentServerName); + Component.FRIEND_LIST.scrollPane.viewport.label = null; + PlayerListEntry prevEntry = null; + + for (final PlayerListEntry entry : Component.FRIEND_LIST.entries.children) { + final boolean isNew = entry.children == null; + if (isNew) { + entry.playerNameLabel = new Component<>(Component.UNSELECTED_LABEL_DARK_2); + entry.addChild(entry.playerNameLabel); + entry.serverNameLabel = new Component<>(Component.UNSELECTED_LABEL_DARK_1); + entry.addChild(entry.serverNameLabel); + entry.displayNameChangedIcon = new Component<>(Component.UNSELECTED_LABEL_DARK_2); + entry.addChild(entry.displayNameChangedIcon); + entry.serverNameLabel.textAlignment = Font.HorizontalAlignment.RIGHT; + entry.recursivelySet_H(); + } + + entry.width = Component.FRIEND_LIST.entries.width; + final int statusColor; + final int mouseOverStatusColor; + if (entry.serverName == null) { + statusColor = 0xcc0000; + mouseOverStatusColor = 0xff6666; + } else if (entry.serverName.equals(currentServerName)) { + statusColor = 0x00cc00; + mouseOverStatusColor = 0x66ff66; + } else { + statusColor = 0xcccc00; + mouseOverStatusColor = 0xffff66; + } + + final boolean displayNameChanged = entry.previousDisplayName != null && !entry.previousDisplayName.equals(""); + if (displayNameChanged) { + entry.displayNameChangedIcon.sprite = Component.DISPLAY_NAME_CHANGED; + entry.displayNameChangedIcon.mouseOverTextColor = mouseOverStatusColor; + entry.displayNameChangedIcon.setBounds(0, 0, Component.DISPLAY_NAME_CHANGED.offsetX + 3, Component.LABEL_HEIGHT); + } + + entry.playerNameLabel.textColor = entry.serverNameLabel.textColor = statusColor; + entry.playerNameLabel.mouseOverTextColor = entry.serverNameLabel.mouseOverTextColor = mouseOverStatusColor; + entry.playerNameLabel._qb = entry.serverNameLabel._qb = mouseOverStatusColor; + entry.playerNameLabel._ab = entry.serverNameLabel._ab = mouseOverStatusColor; + int playerNameX = 0; + final int serverNameWidth = 80; + int playerNameWidth = entry.width - serverNameWidth - 2; + if (displayNameChanged) { + playerNameX = Component.DISPLAY_NAME_CHANGED.offsetX + 3; + playerNameWidth -= playerNameX; + } + + entry.playerNameLabel.label = playerNameWidth <= 0 ? entry.playerDisplayName : entry.playerNameLabel.font.truncateWithEllipsisToFit(entry.playerDisplayName, playerNameWidth); + entry.playerNameLabel.setBounds(playerNameX, 0, playerNameWidth, Component.LABEL_HEIGHT); + entry.serverNameLabel.label = entry.serverName == null ? StringConstants.OFFLINE : entry.serverName; + entry.serverNameLabel.setBounds(entry.width - serverNameWidth, 0, serverNameWidth, Component.LABEL_HEIGHT); + final boolean playerNameTruncated = !entry.playerNameLabel.label.equals(entry.playerDisplayName); + if (!var3) { + entry._gb = Component.LABEL_HEIGHT - entry.height; + } + + if (isNew) { + Component.FRIEND_LIST.entries.placeAfter(prevEntry, entry); + } + + if (entry.displayNameChangedIcon != null && entry.displayNameChangedIcon.isMouseOverTarget) { + ClientLobbyRoom.currentTooltip = entry.previousDisplayName; + } else if (entry.clickButton != MouseState.Button.NONE) { + final String playerName = entry.playerDisplayName; + showContextMenu(Component.FRIEND_LIST.scrollPane, entry, 0L, playerName, null, -1, null); + if (entry.serverName != null && !isComposingChatMessageTo(ContextMenu.openInstance.playerName) && !cannotChat) { + if (!JagexApplet.canOnlyQuickChat) { + ContextMenu.openInstance.view.addItem(Strings.format(StringConstants.SEND_PM_TO_X, playerName), ContextMenu.ClickAction.SEND_PRIVATE_MESSAGE); + } + ContextMenu.openInstance.view.addItem(Strings.format(StringConstants.SEND_QC_TO_X, playerName), ContextMenu.ClickAction.SEND_PRIVATE_MESSAGE_QC); + } + + clickedEntry = entry; + } else if (entry.playerNameLabel.isMouseOverTarget && playerNameTruncated) { + ClientLobbyRoom.currentTooltip = entry.playerDisplayName; + } + + prevEntry = entry; + } + + if (Component.FRIEND_LIST.addButton.clickButton != MouseState.Button.NONE) { + AddOrRemovePlayerPopup.openInstance = new AddOrRemovePlayerPopup(Component.FRIEND_LIST.addButton.x2, Component.FRIEND_LIST.addButton.y2, Component.FRIEND_LIST.addButton.width, Component.FRIEND_LIST.addButton.height, StringConstants.ENTER_FRIEND_ADD, Component.POPUP, Component.LABEL, Component.LABEL); + AddOrRemovePlayerPopup.action = AddOrRemovePlayerPopup.Action.ADD_FRIEND; + } + if (Component.FRIEND_LIST.removeButton.clickButton != MouseState.Button.NONE) { + AddOrRemovePlayerPopup.openInstance = new AddOrRemovePlayerPopup(Component.FRIEND_LIST.removeButton.x2, Component.FRIEND_LIST.removeButton.y2, Component.FRIEND_LIST.removeButton.width, Component.FRIEND_LIST.removeButton.height, StringConstants.ENTER_FRIEND_DEL, Component.POPUP, Component.LABEL, Component.LABEL); + AddOrRemovePlayerPopup.action = AddOrRemovePlayerPopup.Action.REMOVE_FRIEND; + } + } else { + Component.FRIEND_LIST_PANEL.enabled = false; + Component.SERVER_INFO_LABEL.label = StringConstants.PLEASE_WAIT; + if (PlayerListEntry.serverStatus == PlayerListEntry.ServerStatus.LOADING) { + Component.FRIEND_LIST.scrollPane.viewport.label = StringConstants.CONNECTING_TO_FRIEND_SERVER_TWO_LINE; + } else { + Component.FRIEND_LIST.scrollPane.viewport.label = StringConstants.LOADING; + } + crunch(Component.FRIEND_LIST.entries); + } + + return clickedEntry; + } + + public static void dismissContextMenu() { + if (ContextMenu.openInstance != null && ContextMenu.openInstance.target != null) { + ContextMenu.openInstance.target.selected = false; + } + currentContextMenuParent = null; + ContextMenu.openInstance = null; + } + + private static void a969be() { + localPlayerId = -1L; + ratedLobbyRoom = null; + unratedLobbyRoom = null; + playerSeatsFilledBitmap = new byte[(NUM_PLAYERS_OPTION_VALUES.length + 7) / 8]; + justRecievedRoomDetailsFromServer = false; + + int totalGameoptChoices = Arrays.stream(GAMEOPT_CHOICES_COUNTS).sum(); + totalGameoptChoices = (totalGameoptChoices + 7) / 8; + gameoptChoicesBitmap = new byte[totalGameoptChoices]; + + if (Component.INVITE_PLAYER_LIST_SCROLL_PANE.content.children == null) { + Component.INVITE_PLAYER_LIST_SCROLL_PANE.content.children = new ArrayList<>(); + } + + LobbyPlayer.online = Component.INVITE_PLAYER_LIST_SCROLL_PANE.content.children; + LobbyPlayer.online.clear(); + LobbyPlayer.onlineMap = new HashMap<>(); + playerRating = -1; + joinRequestCount = 0; + ContextMenu.roomShowingPlayers = 0; + if (Component.GAME_LIST_SCROLL_PANE.content.children == null) { + Component.GAME_LIST_SCROLL_PANE.content.children = new ArrayList<>(); + } + + ClientLobbyRoom.rooms = Component.GAME_LIST_SCROLL_PANE.content.children; + ClientLobbyRoom.rooms.clear(); + ClientLobbyRoom.roomsMap = new HashMap<>(); + if (Component.JOINED_PLAYERS_TABLE.content.children == null) { + Component.JOINED_PLAYERS_TABLE.content.children = new ArrayList<>(); + } + + LobbyPlayer.joinedPlayers = Component.JOINED_PLAYERS_TABLE.content.children; + LobbyPlayer.joinedPlayers.clear(); + LobbyPlayer.joinedPlayersMap = new HashMap<>(8); + cannotStartGameUntil = 0L; + } + + private static SampledAudioChannel createAudioChannel(final int i, int var3) { + if (i < 0 || i >= 2) { + throw new IllegalArgumentException(); + } + + if (var3 < 256) { + var3 = 256; + } + + try { + final SampledAudioChannel channel = new SampledAudioChannel(); + channel.data = new int[512]; + channel._b = var3; + channel._g = (var3 & 0xfffffc00) + 0x400; + if (channel._g > 0x4000) { + channel._g = 0x4000; + } + + channel.open(channel._g); + if (AudioThread.instance == null) { + AudioThread.instance = new AudioThread(MessagePumpThread.instance); + MessagePumpThread.instance.sendSpawnThreadMessage(AudioThread.instance, 10); + } + + if (AudioThread.instance != null) { + if (AudioThread.instance.channels[i] != null) { + throw new IllegalArgumentException(); + } + + AudioThread.instance.channels[i] = channel; + } + + return channel; + } catch (final LineUnavailableException e) { + throw new RuntimeException(e); + } + } + + public static void closeQuickChat() { + isQuickChatOpen = false; + if (_dmrh != null) { + _dmrh.close(); + } + if (currentChatChannel != Channel.LOBBY) { + discardTypedChatMessage(); + } + _cvcm = 0; + } + + private static ChatMessage a249chmr(final int mouseWheelRotation, final int var2) { + ChatMessage var4 = null; + Component._jiI.content.children.clear(); + int var5 = 0; + int var6 = 0; + + int var7; + for (var7 = chatMessageCount - 1; var7 >= 0; --var7) { + final ChatMessage var8 = chatMessages[var7]; + boolean var9 = false; + if (!cannotChat && _kpi > var5) { + final ChatMessage.FilterLevel var10 = ContextMenu.getChatChannelFilter(var8.channel); + if (var10.lessThanOrEqual(var8.a410()) && (var8._h || !PlayerListEntry.isIgnored(var8.senderName))) { + var9 = true; + } + } + + if (var9) { + if (var8.component == null || ContextMenu._fpv) { + + final String var15 = a614hg(var8); + final String var11 = var15 + Font.escapeTags(var8.message); + final int var12 = a421jl(var8); + var8.component = new Component<>(Component.UNSELECTED_LABEL, var11); + var8.component.font = Component.CHAT_FONT; + var8.component.mouseOverTextColor = -(var12 >> 1 & 8355711) + var12 + (8355711 & Component.UNSELECTED_LABEL.mouseOverTextColor >> 1); + var8.component.textColor = var12; + var6 += Component.LABEL_HEIGHT; + var8.component._qb = -(8355711 & var12 >> 1) + var12 + (8355711 & Component.UNSELECTED_LABEL._qb >> 1); + } + + ++var5; + } else { + var8.component = null; + } + } + + var7 = 0; + + int var13; + for (var13 = 0; chatMessageCount > var13; ++var13) { + final ChatMessage var14 = chatMessages[var13]; + if (var14.component != null) { + Component._jiI.content.addChild(var14.component); + var14.component.setBounds(var2, var7, var14.component.e474(), Component.LABEL_HEIGHT); + if (var14.component.clickButton != MouseState.Button.NONE) { + var4 = var14; + } + + var7 += Component.LABEL_HEIGHT; + } + } + + var13 = -var7 + var6 + Component._jiI.content.height + Component._jiI.content._gb; + Component._jiI.content.height -= var13; + Component._jiI.content.y += var13; + if (ContextMenu._fpv) { + Component._jiI.content.height = var7; + } + + Component._jiI.content._gb = -Component._jiI.content.height + var7; + if (ContextMenu._fpv) { + ContextMenu._fpv = false; + Component._jiI.content._w = 0; + _K = true; + Component._jiI.content.y = -Component._jiI.content.height + Component._jiI.viewport.height; + } + + if (isChatboxSelected && _faX != null) { + _K = true; + } + + final int var16 = Component._jiI.viewport.height - Component._jiI.content.height - Component._jiI.content._gb; + if (_K) { + Component._jiI.content._w = var16 - Component._jiI.content.y; + } + + Component._jiI.a795(mouseWheelRotation * 2 * Component.LABEL_HEIGHT, Component.LABEL_HEIGHT); + _K = var16 == Component._jiI.content._w + Component._jiI.content.y; + return var4; + } + + private static String a803(String var0) { + final int var1 = a776wd(modLevel, adminLevel); + if (var1 == 1) { + var0 = "" + var0; + } + + if (var1 == 2) { + var0 = "" + var0; + } + + return var0; + } + + private static void crunch(final Component var1) { + for (final Component var2 : var1.children) { + var2.height = 0; + var2._gb = 0; + var2._w = 0; + var2.y = 0; + } + var1.height = 0; + var1._w = 0; + var1.y = 0; + var1._gb = 0; + } + + private static void a487oq(final boolean canCreateAccount) { + if (!isAnonymous) { + throw new IllegalStateException(); + } + CommonUI.switchToLogin(canCreateAccount, false); + connectionState = ConnectionState.NOT_CONNECTED; + } + + private static void a093oq() { + for (final SetProfileRequest var1 : JagexApplet.profileSetRequests) { + C2SPacket.sendProfileSet(var1); + } + JagexApplet.getProfileResponses.forEach(var2 -> C2SPacket.sendProfileGet()); + } + + private static boolean a154vc() { + return (fullScreenCanvas != null || hadFocus) && (8 & currentTick) == 0; + } + + private static void b423jf() { + Menu.isFullscreenDialogOpen = false; + Menu._hmp = null; + Menu._nld = null; + Menu._kpo = null; + Menu._kdb = null; + } + + private static void tickLobbyBrowser(final boolean mouseNotYetHandled, final boolean inGame) { + Component.layoutLobbyBrowserPanels(); + + if (playerRating < 0) { + Component.YOUR_RATING_LABEL.label = null; + } else { + Component.YOUR_RATING_LABEL.label = Strings.format(StringConstants.YOUR_RATING_IS_X, Integer.toString(playerRating)); + } + + Component.lobbyBrowserLeftPanel.rootProcessMouseEvents(mouseNotYetHandled && !inGame && !showYouHaveBeenKickedDialog && unratedLobbyRoom == null && ratedLobbyRoom == null); + Component.LOBBY_RIGHT_PANEL.rootProcessMouseEvents(mouseNotYetHandled && !inGame && !showYouHaveBeenKickedDialog && unratedLobbyRoom == null && ratedLobbyRoom == null); + Component.YOU_HAVE_BEEN_KICKED_DIALOG.rootProcessMouseEvents(mouseNotYetHandled && !inGame && showYouHaveBeenKickedDialog); + Component.lobbyBrowserTabbedPlayerList.view.f487(); + if (Component.RETURN_TO_MAIN_MENU_BUTTON.clickButton != MouseState.Button.NONE) { + returnToMainMenuClicked = true; + } + + if (Component.PLAY_RATED_GAME_BUTTON.clickButton != MouseState.Button.NONE) { + if (_hmo || JagexApplet.membershipLevel > 0 || adminLevel >= 2 && keysDown[12]) { + C2SPacket.playRatedGame(); + } else { + _ucB = true; + } + } + + if (Component.CREATE_UNRATED_GAME_BUTTON.clickButton != MouseState.Button.NONE) { + C2SPacket.createUnratedGame(); + } + + if (Component.YOU_HAVE_BEEN_KICKED_OK_BUTTON.clickButton != MouseState.Button.NONE) { + showYouHaveBeenKickedDialog = false; + } + } + + public static void f423fr() { + final int var0 = (int) (1600.0D * (1.0D + Math.cos((float) currentTick / 500.0F))); + final int var1 = (int) (1600.0D * (-Math.sin((float) currentTick / 500.0F) + 1.0D)); + if (renderQuality.antialiasStarfieldBackground) { + a034il(var0, var1, STAR_FIELD); + Drawing.horizontalLine(0, 0, SCREEN_WIDTH, 0); + } else { + STAR_FIELD.c093(-var0 >> 4, -var1 >> 4); + } + } + + private static void a034il(int var0, int var2, final Sprite var3) { + if (_cfa == null || _cfa.length != Drawing.width) { + _cfa = new int[Drawing.width]; + } + + final int var4 = var2 & 15; + var2 >>= 4; + final int var5 = var0 & 15; + var0 >>= 4; + int var12 = 0; + int var13 = var3.width * var2 + var0; + final int var14 = -Drawing.width + var3.width; + + for (int var15 = -Drawing.height; var15 < 0; var13 += var14) { + int var16 = 0; + + for (int var17 = Drawing.width - 1; var17 >= 0; --var17) { + final int var6 = var3.pixels[var13]; + final int var8 = var6 & '\uff00'; + final int var7 = var6 & 16711935; + final int var10 = 267390960 & var5 * var7; + final int var11 = var5 * var8 & 1044480; + final int var9 = var11 | var10; + final int i = var16 + var9; + final int i1 = 267390960 & i; + var16 = (var6 << 4) - var9; + final int i2 = i & 1044480; + final int i3 = -16711936 & var4 * i1; + final int i4 = 16711680 & i2 * var4; + final int i5 = i3 | i4; + Drawing.screenBuffer[var12] = _cfa[var17] + i5 >> 8; + _cfa[var17] = (i << 4) - i5; + ++var12; + ++var13; + } + + ++var15; + } + } + + private static int a421jl(final ChatMessage message) { + int color = _hoc; + if (message.channel == Channel.PRIVATE) { + if (!message._h) { + if (message._l == 0 && message._e == 0) { + color = Component.CHANNEL_TEXT_COLORS_1[message.channel.ordinal()]; + } else { + color = Component.CHANNEL_TEXT_COLORS_2[message.channel.ordinal()]; + } + } + } else if (message.channel == Channel.CHANNEL_5) { + color = Component.CHANNEL_TEXT_COLORS_2[message.channel.ordinal()]; + } else if (message.senderId == localPlayerId) { + color = Component.CHANNEL_TEXT_COLORS_1[message.channel.ordinal()]; + } else { + color = Component.CHANNEL_TEXT_COLORS_2[message.channel.ordinal()]; + } + + return color; + } + + private static void a540ta(boolean var0) { + if (isPopupOpen()) { + var0 = false; + } + + a877di(var0); + a893ml(var0); + } + + private static void a877di(final boolean var0) { + Drawing.withLocalContext(() -> { + Drawing.expandBoundsToInclude(Drawing.width - SCREEN_WIDTH >> 1, 0, Drawing.width + SCREEN_WIDTH >> 1, Drawing.height); + if (lobbyBrowserTransitionCounter > 0) { + if (LOBBY_ICON != null) { + LOBBY_ICON.c093(Component.lobbyBrowserLeftPanel.x, 0); + } + + Component.lobbyBrowserLeftPanel.b540(var0 && !showYouHaveBeenKickedDialog); + Component.LOBBY_RIGHT_PANEL.b540(var0 && !showYouHaveBeenKickedDialog); + } + + if (ratedLobbyRoomTransitionCounter > 0 || unratedLobbyRoomTransitionCounter > 0) { + if (LOBBY_ICON != null) { + LOBBY_ICON.c093(lobbyRoomLeftPanel.x, 0); + } + + lobbyRoomLeftPanel.b540(var0 && !invitePlayersDialogOpen); + Component.GAME_INFO_CONTAINER.b540(var0 && !invitePlayersDialogOpen); + } + }); + } + + private static void a366fa(int var0) { + _flf = var0; + if (_pgJ != 20) { + final int var1 = 400; + final int var2 = -(_pgJ * _pgJ) + var1; + var0 += (-var0 + _dmgm) * var2 / var1; + } + + Component._tgc.setBounds(_tmh, var0, SCREEN_WIDTH, 120); + a370qc(_dmgm - 24, _tga, ClientLobbyRoom._qob); + } + + private static void a370qc(final int var0, final int var2, final int var5) { + Component._uaf.setBounds(5, 0, SCREEN_WIDTH, var0); + if (_dmrh != null) { + _dmrh.a669(var2, var0, var2 - _cvcm, var5, var0); + } + } + + private static void tickLoadProfile() { + if (!areAchievementsInitialized && achievementRequest == null) { + achievementRequest = JagexApplet.createAchievementRequest(); + } + + if (!loadedProfile) { + if (request == null) { + request = loadProfile(); + } + + if (request.completed) { + if (request.data != null) { + receiveProfile(request.data); + } + + saveProfile(); + if (GameUI.currentSettings == -1) { + GameUI.currentSettings = GameUI.lastSavedSettings; + } + + loadedProfile = true; + } + } + } + + private static void receiveProfile(final byte[] data) { + if (data[0] >= 0) { + GameUI.lastSavedSettings = data[1]; + } + } + + private static void tickUnratedLobbyRoom(final boolean mouseNotYetHandled, final boolean canStart, final boolean inGame) { + layoutLobbyRoomPanels(unratedLobbyRoomTransitionCounter); + if (unratedLobbyRoom != null) { + Component.RETURN_TO_LOBBY_BUTTON.enabled = true; + Component.INVITE_PLAYERS_BUTTON.height = 0; + final Component var5 = Component.INVITE_PLAYERS_BUTTON; + var5.width = 0; + final Component var6 = Component.FIND_OPPONENTS_BUTTON; + Component.FIND_OPPONENTS_BUTTON.height = 0; + var6.width = 0; + Component.WAITING_TO_START_LABEL.height = 0; + final Component var7 = Component.WAITING_TO_START_LABEL; + var7.width = 0; + final Component var8; + int var19; + if (isCurrentRoomOwner()) { + Component.GAME_OWNER_HEADING.label = StringConstants.YOUR_GAME.toUpperCase(); + var19 = (Component.GAME_INFO_CONTAINER.width + 2) / 2; + Component.INVITE_PLAYERS_BUTTON.setBounds(0, Component.GAME_INFO_CONTAINER.height - 40, var19 - 2, 40); + if (unratedLobbyRoom.joinedPlayerCount < unratedLobbyRoom.maxPlayerCount) { + Component.INVITE_PLAYERS_BUTTON.label = StringConstants.MU_INVITE_PLAYERS.toUpperCase(); + Component.INVITE_PLAYERS_BUTTON.enabled = true; + } else { + Component.INVITE_PLAYERS_BUTTON.label = StringConstants.GAME_FULL.toUpperCase(); + Component.INVITE_PLAYERS_BUTTON.enabled = false; + } + + Component.INVITE_PLAYERS_BUTTON.nineSliceSprites = Component.BIG_BUTTON.nineSliceSprites; + if (joinRequestCount > 0) { + final String joinRequestsLabel; + if (joinRequestCount == 1) { + joinRequestsLabel = StringConstants.JOIN_REQUESTS_ONE; + } else { + joinRequestsLabel = Strings.format(StringConstants.JOIN_REQUESTS_MANY, Integer.toString(joinRequestCount)); + } + + if ((_ssw & 16) == 0 && !invitePlayersDialogOpen) { + Component.INVITE_PLAYERS_BUTTON.nineSliceSprites = Component.BIG_BUTTON.mouseOverNineSliceSprites; + } + + Component.INVITE_PLAYERS_BUTTON.label = Component.INVITE_PLAYERS_BUTTON.label + "
" + joinRequestsLabel; + } + + Component.FIND_OPPONENTS_BUTTON.setBounds(var19, Component.GAME_INFO_CONTAINER.height - 40, -var19 + Component.GAME_INFO_CONTAINER.width, 40); + Component.FIND_OPPONENTS_BUTTON.label = StringConstants.START_GAME.toUpperCase(); + Component.FIND_OPPONENTS_BUTTON.enabled = canStart && cannotStartGameUntil == 0L; + var8 = Component.FIND_OPPONENTS_BUTTON; + int var20 = 2; + int var14; + int var15; + int var16; + int var17; + boolean var21; + if (_peD != null) { + if (_lrc == null) { + _lrc = new byte[GAMEOPT_CHOICES_COUNTS.length]; + _ekF = new boolean[GAMEOPT_CHOICES_COUNTS.length]; + } + + for (int var11 = 0; var11 < GAMEOPT_CHOICES_COUNTS.length; ++var11) { + _ekF[var11] = false; + } + + for (var20 = 0; var20 < 2; ++var20) { + var21 = false; + + label323: + for (final int[] var13 : _peD) { + for (var14 = 0; var14 < var13.length; var14 += 2) { + var15 = var13[var14]; + var16 = var13[var14 + 1]; + if (var15 == -1) { + var17 = var20 != 0 ? unratedLobbyRoom.joinedPlayerCount : unratedLobbyRoom.maxPlayerCount; + if (var16 != var17) { + continue label323; + } + } else if ((255 & unratedLobbyRoom.gameSpecificOptions[var15]) != var16) { + continue label323; + } + } + + var21 = true; + var14 = -1; + + for (var15 = 0; var13.length > var15; var15 += 2) { + var16 = var13[var15]; + if (var16 > var14) { + var14 = var16; + } + } + + _ekF[var14] = true; + } + + if (var21) { + break; + } + } + + if (adminLevel >= 2 && keysDown[12]) { + var20 = 2; + } + } + + boolean var23; + int var24; + if (var20 < 2) { + Component.FIND_OPPONENTS_BUTTON.enabled = false; + if (Component.FIND_OPPONENTS_BUTTON.isMouseOver) { + String var22 = null; + var23 = false; + + String var26; + for (var24 = 0; GAMEOPT_CHOICES_COUNTS.length > var24; ++var24) { + if (_ekF[var24]) { + var26 = "" + StringConstants.GAMEOPT_LABELS[var24] + ""; + if (var22 == null) { + var22 = var26; + } else { + var22 = var22 + ", " + var26; + var23 = true; + } + } + } + + final String var25; + if (var20 == 0) { + var25 = StringConstants.GAMEOPT_UNSELECTED_OPTIONS; + if (var23) { + var26 = StringConstants.GAMEOPT_PLEASE_SELECT_OPTION_2 + var22; + } else { + var26 = Strings.format(StringConstants.GAMEOPT_PLEASE_SELECT_OPTION_1, var22); + } + } else { + var25 = StringConstants.GAMEOPT_BADNUMPLAYERS; + if (var23) { + var26 = StringConstants.GAMEOPT_INVITE_PLAYERS_OR_TRY_CHANGING_2 + var22; + } else { + var26 = Strings.format(StringConstants.GAMEOPT_INVITE_PLAYERS_OR_TRY_CHANGING_1, var22); + } + } + + ClientLobbyRoom.currentTooltip = "" + var25 + "
" + var26; + } + } + } else { + final String ownerName = unratedLobbyRoom.ownerName; + Component.GAME_OWNER_HEADING.label = Strings.format(StringConstants.XS_GAME, ownerName).toUpperCase(); + Component.WAITING_TO_START_LABEL.setBounds(0, Component.GAME_INFO_CONTAINER.height - 40, Component.GAME_INFO_CONTAINER.width, 40); + Component.WAITING_TO_START_LABEL.label = Strings.format(StringConstants.WAITING_FOR_X_TO_START_GAME, ownerName); + var8 = Component.WAITING_TO_START_LABEL; + } + + if (cannotStartGameUntil != 0L) { + var19 = (int) (cannotStartGameUntil - PseudoMonotonicClock.currentTimeMillis()); + var19 = (var19 + 999) / 1000; + if (var19 < 1) { + var19 = 1; + } + + var8.label = Strings.format(StringConstants.GAME_OPTS_CHANGED, Integer.toString(var19)); + } + + Component.JOINED_PLAYER_COUNT_LABEL.label = Strings.format(StringConstants.PLAYERS_X_OF_Y, Integer.toString(unratedLobbyRoom.joinedPlayerCount), Integer.toString(unratedLobbyRoom.maxPlayerCount)); + } + + lobbyRoomLeftPanel.rootProcessMouseEvents(mouseNotYetHandled && !inGame && !invitePlayersDialogOpen); + Component.GAME_INFO_CONTAINER.rootProcessMouseEvents(mouseNotYetHandled && !inGame && !invitePlayersDialogOpen); + invitePlayersDialog.rootProcessMouseEvents(mouseNotYetHandled && !inGame && invitePlayersDialogOpen); + lobbyRoomTabbedPlayerList.view.f487(); + + if (unratedLobbyRoom != null) { + if (Component.RETURN_TO_LOBBY_BUTTON.clickButton != MouseState.Button.NONE) { + C2SPacket.requestToLeaveRoom(unratedLobbyRoom.roomId); + } + + if (Component.FIND_OPPONENTS_BUTTON.clickButton != MouseState.Button.NONE) { + findOpponentsButtonClicked = true; + } + + if (Component.INVITE_PLAYERS_BUTTON.clickButton != MouseState.Button.NONE) { + invitePlayersDialogOpen = true; + } + + if (Component.CLOSE_BUTTON_2.clickButton != MouseState.Button.NONE) { + invitePlayersDialogOpen = false; + } + + a626sc(false, unratedLobbyRoom); + } + } + + private static void a626sc(final boolean var0, final ClientLobbyRoom room) { + final boolean canChange = var0 ? !justRecievedRoomDetailsFromServer : (isCurrentRoomOwner() && !room.hasStarted); + + boolean didChangeOptions = false; + if (!var0) { + for (int i = 0; i < 5; ++i) { + final ActionButton button = Component.GAME_OPTIONS_BUTTONS[0][i + 1]; + if (canChange && button.clickButton != MouseState.Button.NONE && room.whoCanJoin != i) { + room.whoCanJoin = i; + didChangeOptions = true; + } + button.enabled = canChange; + button.selected = room.whoCanJoin == i; + } + + if (Component.GAME_OPTIONS_BUTTONS[0][2].isMouseOver) { + if (isCurrentRoomOwner()) { + ClientLobbyRoom.currentTooltip = StringConstants.THIS_IS_RUNESCAPE_CLAN; + } else { + ClientLobbyRoom.currentTooltip = Strings.format(StringConstants.THIS_IS_RUNESCAPE_CLAN_NOT_OWNER, unratedLobbyRoom.ownerName); + } + } + } + + for (int i = var0 ? -1 : 0; i < NUM_PLAYERS_OPTION_VALUES.length; ++i) { + final ActionButton button = Component.GAME_OPTIONS_BUTTONS[1][i + 1]; + if (canChange && button.clickButton != MouseState.Button.NONE) { + if (var0) { + if (i == -1) { + Arrays.fill(playerSeatsFilledBitmap, (byte) 0); + } else { + playerSeatsFilledBitmap[i >> 3] = (byte) ((int) playerSeatsFilledBitmap[i >> 3] ^ (1 << (i & 7))); + } + } else { + final int playerCount = NUM_PLAYERS_OPTION_VALUES[i]; + if (room.maxPlayerCount != playerCount) { + room.maxPlayerCount = playerCount; + didChangeOptions = true; + } + } + } + + if (!var0) { + button.selected = room.maxPlayerCount == NUM_PLAYERS_OPTION_VALUES[i]; + } else if (i == -1) { + Component.GAME_OPTIONS_BUTTONS[1][0].selected = true; + + for (int j = 0; j < NUM_PLAYERS_OPTION_VALUES.length; ++j) { + Component.GAME_OPTIONS_BUTTONS[1][0].selected &= (playerSeatsFilledBitmap[j / 8] & 1 << (j & 7)) == 0; + } + } else { + button.selected = (playerSeatsFilledBitmap[i / 8] & 1 << (i & 7)) != 0; + } + + button.enabled = canChange; + } + + for (int i = var0 ? 0 : 1; i < 3; ++i) { + final ActionButton button = Component.GAME_OPTIONS_BUTTONS[2][i]; + if (canChange && button.clickButton != MouseState.Button.NONE) { + if (var0) { + if (i == 0) { + allowSpectateSelection = 0; + } else { + allowSpectateSelection ^= i; + } + } else if (room.allowSpectate != i) { + room.allowSpectate = i; + didChangeOptions = true; + } + } + + button.enabled = canChange; + if (var0) { + if (i == 0) { + button.selected = allowSpectateSelection == 0; + } else { + button.selected = (i & allowSpectateSelection) != 0; + } + } else { + button.selected = (i & room.allowSpectate) != 0; + } + } + + if (var0) { + for (int i = 0; i < 2; ++i) { + final ActionButton button = Component.GAME_OPTIONS_BUTTONS[3][i]; + if (canChange && button.clickButton != MouseState.Button.NONE) { + maxAiPlayersSelection = i; + } + + button.enabled = canChange; + button.selected = maxAiPlayersSelection == i; + } + } + + int var6 = 0; + for (int i = 0; i < GAMEOPT_CHOICES_COUNTS.length; ++i) { + final ActionButton[] buttons = Component.GAME_OPTIONS_BUTTONS[i + 4]; + for (int j = var0 ? -1 : 0; j < buttons.length - 1; ++j) { + boolean var31 = false; + _wgd = true; + if (j >= 0 && _peD != null && (!var0 || !justRecievedRoomDetailsFromServer)) { + _wgd = false; + if (_lrc == null) { + _lrc = new byte[GAMEOPT_CHOICES_COUNTS.length]; + _ekF = new boolean[GAMEOPT_CHOICES_COUNTS.length]; + } + + _sbh = false; + + for (int var17 = 0; var17 < i; ++var17) { + _ekF[var17] = false; + } + + a068js(-1, i, 0, var0, j, -1); + if (adminLevel >= 2 && keysDown[12]) { + _wgd = true; + } + + if (!_wgd) { + var31 = true; + } + } + + final ActionButton button = buttons[j + 1]; + int var18; + if (canChange && button.clickButton != MouseState.Button.NONE) { + if (!var0) { + if (!var31 && (byte) j != room.gameSpecificOptions[i]) { + room.gameSpecificOptions[i] = (byte) j; + didChangeOptions = true; + } + } else if (j == -1) { + for (var18 = var6; var18 < buttons.length + (var6 - 1); ++var18) { + final int var11 = ~(1 << (var18 & 7)); + gameoptChoicesBitmap[var18 / 8] = (byte) ((int) gameoptChoicesBitmap[var18 / 8] & var11); + } + } else { + gameoptChoicesBitmap[(j + var6) / 8] = (byte) ((int) gameoptChoicesBitmap[(j + var6) / 8] ^ 1 << (j + var6 & 7)); + } + } + + if (var0 && var31) { + final int var11 = ~(1 << (7 & var6 + j)); + gameoptChoicesBitmap[(j + var6) / 8] = (byte) ((int) gameoptChoicesBitmap[(j + var6) / 8] & var11); + } + + if (j >= 0 && button.isMouseOver) { + final String optionName = StringConstants.GAMEOPT_NAMES[i] != null ? StringConstants.GAMEOPT_NAMES[i][j] : null; + final String optionTooltip = GAMEOPT_TOOLTIPS[i] != null ? GAMEOPT_TOOLTIPS[i][j] : null; + String maybeOptionTooltip = null; + if (optionTooltip != null && !optionTooltip.equals(optionName)) { + maybeOptionTooltip = optionTooltip; + } + + String var21 = null; + String var34; + if (canChange && !_wgd) { + var34 = null; + boolean var23 = false; + if (_sbh) { + var34 = "" + StringConstants.MU_OPTIONS_PLAYERS + ""; + } + + for (int var24 = 0; i > var24; ++var24) { + if (_ekF[var24]) { + final String var25 = "" + StringConstants.GAMEOPT_LABELS[var24] + ""; + if (var34 == null) { + var34 = var25; + } else { + var34 = var34 + ", " + var25; + var23 = true; + } + } + } + + if (var23) { + var21 = StringConstants.GAMEOPT_CANNOT_BE_COMBINED_2 + var34; + } else { + var21 = Strings.format(StringConstants.GAMEOPT_CANNOT_BE_COMBINED_1, var34); + } + } + + if (var21 != null) { + var21 = "" + var21; + var21 = Component.a369(var21); + if (maybeOptionTooltip == null) { + maybeOptionTooltip = var21; + } else { + maybeOptionTooltip = maybeOptionTooltip + "
" + var21; + } + } + + if (maybeOptionTooltip != null) { + ClientLobbyRoom.currentTooltip = maybeOptionTooltip; + } + } + + if (var0) { + if (j == -1) { + button.selected = true; + + for (var18 = var6; var18 < buttons.length + var6 - 1; ++var18) { + button.selected &= (gameoptChoicesBitmap[var18 / 8] & 1 << (var18 & 7)) == 0; + } + } else { + button.selected = (gameoptChoicesBitmap[(var6 + j) / 8] & 1 << (7 & j + var6)) != 0; + } + } else { + button.selected = _wgd && room.gameSpecificOptions[i] == (byte) j; + } + + button.enabled = canChange && !var31; + } + + var6 += GAMEOPT_CHOICES_COUNTS[i]; + } + + if (didChangeOptions && !var0) { + C2SPacket.updateRoomOptions(); + } + } + + private static void a068js(final int var0, final int var3, int var4, final boolean var5, final int var6, int var7) { + if (var3 > var0) { + final ActionButton[] var8 = Component.GAME_OPTIONS_BUTTONS[var0 != -1 ? 4 + var0 : 1]; + boolean var9 = true; + if (var5) { + int var10; + if (var0 == -1) { + for (var10 = 0; NUM_PLAYERS_OPTION_VALUES.length > var10; ++var10) { + if ((playerSeatsFilledBitmap[var10 / 8] & 1 << (var10 & 7)) != 0) { + var9 = false; + break; + } + } + } else { + for (var10 = 0; var8.length - 1 > var10; ++var10) { + if ((gameoptChoicesBitmap[(var10 + var4) / 8] & 1 << (7 & var4 + var10)) != 0) { + var9 = false; + break; + } + } + + var4 += GAMEOPT_CHOICES_COUNTS[var0]; + } + } + + boolean var17 = false; + + int var11; + for (var11 = 0; (var0 == -1 ? NUM_PLAYERS_OPTION_VALUES.length : var8.length - 1) > var11; ++var11) { + if (var0 == -1) { + var7 = var11; + } else { + _lrc[var0] = (byte) var11; + } + + final boolean var12; + final ActionButton var13 = var8[1 + var11]; + if (var5) { + var12 = var13.selected || var9 && var13.enabled; + } else { + var12 = var0 != -1 ? (255 & unratedLobbyRoom.gameSpecificOptions[var0]) == var11 : NUM_PLAYERS_OPTION_VALUES[var11] == unratedLobbyRoom.maxPlayerCount; + } + + if (var12) { + a068js(1 + var0, var3, var4, var5, var6, var7); + var17 = true; + } + + if (_wgd) { + return; + } + } + + if (!var17) { + for (var11 = 0; var11 < var8.length - 1; ++var11) { + if (var0 == -1) { + var7 = var11; + } else { + _lrc[var0] = (byte) var11; + } + + a068js(var0 + 1, var3, var4, var5, var6, var7); + if (_wgd) { + return; + } + } + } + } else { + boolean var15 = true; + + label148: + for (final int[] var18 : _peD) { + boolean var19 = false; + + int var20; + int var21; + for (var20 = 0; var20 < var18.length; var20 += 2) { + var21 = var18[var20]; + final int var14 = var18[1 + var20]; + if (var21 == -1) { + if (NUM_PLAYERS_OPTION_VALUES[var7] != var14) { + continue label148; + } + } else if (var21 == var0 && var6 == var14) { + var19 = true; + } else if (var0 <= var21 || (_lrc[var21] & 255) != var14) { + continue label148; + } + } + + if (var19 || GAMEOPT_CHOICES_COUNTS.length == var0) { + for (var20 = 0; var18.length > var20; var20 += 2) { + var21 = var18[var20]; + if (var21 == -1) { + _sbh = true; + } else if (var21 < var0) { + _ekF[var21] = true; + } + } + + var15 = false; + } + } + + if (var15) { + _wgd = true; + } + } + + } + + private static void tickLobbyTransitionCounters(final boolean inGame) { + if (inGame || unratedLobbyRoom == null) { + invitePlayersDialogOpen = false; + } + + if (inGame) { + if (lobbyBrowserTransitionCounter > 0) { + --lobbyBrowserTransitionCounter; + } else if (ratedLobbyRoomTransitionCounter > 0) { + --ratedLobbyRoomTransitionCounter; + } else if (unratedLobbyRoomTransitionCounter > 0) { + --unratedLobbyRoomTransitionCounter; + } + } else if (unratedLobbyRoom == null) { + if (ratedLobbyRoom == null) { + if (ratedLobbyRoomTransitionCounter > 0) { + --ratedLobbyRoomTransitionCounter; + } else if (unratedLobbyRoomTransitionCounter > 0) { + --unratedLobbyRoomTransitionCounter; + } else if (lobbyBrowserTransitionCounter < 20) { + if (lobbyBrowserTransitionCounter == 0) { + Component.initializeLobbyBrowserComponents(); + } + + ++lobbyBrowserTransitionCounter; + } + } else if (lobbyBrowserTransitionCounter > 0) { + --lobbyBrowserTransitionCounter; + } else if (unratedLobbyRoomTransitionCounter > 0) { + --unratedLobbyRoomTransitionCounter; + } else if (ratedLobbyRoomTransitionCounter < 20) { + if (ratedLobbyRoomTransitionCounter == 0) { + initializeLobbyRoomComponents(true); + } + + ++ratedLobbyRoomTransitionCounter; + } + } else if (lobbyBrowserTransitionCounter > 0) { + --lobbyBrowserTransitionCounter; + } else if (ratedLobbyRoomTransitionCounter > 0) { + --ratedLobbyRoomTransitionCounter; + } else if (unratedLobbyRoomTransitionCounter < 20) { + if (unratedLobbyRoomTransitionCounter == 0) { + initializeLobbyRoomComponents(false); + } + ++unratedLobbyRoomTransitionCounter; + } + } + + private static void initializeLobbyRoomComponents(final boolean isRated) { + lobbyRoomTabbedPlayerList = isRated + ? new TabbedPlayerListWrapper(StringConstants.MU_CHAT_TIPS, Component.RATED_GAME_TIPS_LABEL) + : new TabbedPlayerListWrapper(StringConstants.MU_CHAT_GAME, Component.JOINED_PLAYERS_PANEL); + lobbyRoomLeftPanel = new Component<>(null); + lobbyRoomLeftPanel.addChild(lobbyRoomTabbedPlayerList.view); + lobbyRoomLeftPanel.addChild(Component.RETURN_TO_LOBBY_BUTTON); + invitePlayersDialog = new Component<>(null); + invitePlayersDialogContents = new Component<>(null); + invitePlayersDialog.addChild(Component.INVITE_PLAYERS_LABEL); + invitePlayersDialog.addChild(invitePlayersDialogContents); + invitePlayersDialogContents.addChild(Component.INVITE_PLAYER_LIST_PANEL); + invitePlayersDialogContents.addChild(Component.CLOSE_BUTTON_2); + layoutLobbyRoom(isRated); + } + + public static void switchMenus() { + if (Menu.currentMenu != Menu.nextMenu) { + if (Menu.currentMenu >= 0) { + Menu.menus[Menu.currentMenu].prepareToSwitchAwayFrom(); + } + + _cjx = _tli; + Menu._ehQ = 0; + Menu.currentMenu = Menu.nextMenu; + if (Menu.nextMenu == Menu.Id.INTRODUCTION) { + IntroAnimation.reset(); + } + + if (Menu.nextMenu == Menu.Id.MAIN && !Sounds.musicTn.a419(currentTrack)) { + a827jo(currentTrack, 0x100000, true); + } + + if (Menu.nextMenu == Menu.Id.LOADING_LOBBY) { + C2SPacket.enterLobby(); + _mdQ = true; + Menu.nextMenu = Menu.currentMenu; + } + + if (_lgb) { + if (ClientGameSession.playSession != null && ClientGameSession.playSession.ui != null) { + ClientGameSession.playSession.ui.destroy(); + } + + if (ClientGameSession.spectateSession != null && ClientGameSession.spectateSession.ui != null) { + ClientGameSession.spectateSession.ui.destroy(); + } + + _lgb = false; + ClientGameSession.playSession = null; + ClientGameSession.spectateSession = null; + } + + if (Menu.discarding) { + Menu.unlockedAchievementsBitmap = 0; + Menu.discarding = false; + } + + if (leavingLobby) { + a423ppi(); + e423ec(); + PlayerListEntry.reset(); + leavingLobby = false; + } + } + } + + private static void a714jc(final Sprite var0) { + Drawing.saveContext(); + _dmgn = new Sprite(128, 128); + _dmgn.installForDrawing(); + var0.draw(0, 0); + final Sprite _ksh = new Sprite(256, 256); + _ksh.installForDrawing(); + _dmgn.b115(0, 0, 256, 256); + Drawing.b669(3, 3, 256, 256); + _lqo = new Sprite(32, 32); + _lqo.installForDrawing(); + _dmgn.g093(); + _jcnk = new Sprite(256, 256); + _jcnk.installForDrawing(); + _dmgn.draw(64, 64); + Drawing.b669(12, 12, 256, 256); + _msb = new Sprite(64, 64); + _msb.installForDrawing(); + _lqo.draw(16, 16); + Drawing.b669(3, 3, 64, 64); + Drawing.restoreContext(); + } + + private static boolean b154chmr() { + final long var1 = PseudoMonotonicClock.currentTimeMillis(); + final long var3 = var1 - _tkz; + if (var3 <= 30000L) { + short var5 = 3000; + if (_vjC < 7) { + if (_vjC < 5) { + if (_vjC >= 3) { + var5 = 6000; + } + } else { + var5 = 9000; + } + } else { + var5 = 12000; + } + + if (var3 <= (long) var5) { + return false; + } else { + ++_vjC; + _tkz = var1; + return true; + } + } else { + _vjC = 0; + _tkz = var1; + return true; + } + } + + private static void tickQuickChat(final boolean var0) { + QuickChatHelpPanel.tick(); + tickQuickChatSelector(var0); + } + + private static void tickQuickChatSelector(boolean var1) { + if (isQuickChatOpen) { + Component._uaf.rootProcessMouseEvents(var1); + final boolean var4 = _dmrh.f491(); + if (JagexApplet.mouseButtonJustClicked != MouseState.Button.NONE && !var4) { + closeQuickChatIfOpen(); + var1 = false; + } + + if (var1) { + _dmrh.a599(); + } + + if (var4) { + Component._uaf.rootProcessMouseEvents(var1); + } + + final int var5 = _dmrh.g474() + _dmrh.x2; + if (var5 <= SCREEN_WIDTH) { + if (var5 < 635 && _cvcm > 0) { + _cvcm -= 5; + } + } else { + _cvcm += 5; + } + + } + } + + private static void i150ak() { + if (lobbyBrowserTransitionCounter <= 0) { + if (ratedLobbyRoomTransitionCounter > 0) { + --ratedLobbyRoomTransitionCounter; + } else if (unratedLobbyRoomTransitionCounter > 0) { + --unratedLobbyRoomTransitionCounter; + } + } else { + --lobbyBrowserTransitionCounter; + } + + if (lobbyBrowserTransitionCounter > 0) { + Component.layoutLobbyBrowserPanels(); + } + + if (ratedLobbyRoomTransitionCounter > 0) { + layoutLobbyRoomPanels(ratedLobbyRoomTransitionCounter); + } + + if (unratedLobbyRoomTransitionCounter > 0) { + layoutLobbyRoomPanels(unratedLobbyRoomTransitionCounter); + } + + } + + private static void layoutLobbyRoom(final boolean isRated) { + Component.lastLayoutWidth = Drawing.width; + Component.lastLayoutHeight = Drawing.height; + layoutLobbyRoomPanels(isRated ? ratedLobbyRoomTransitionCounter : unratedLobbyRoomTransitionCounter); + lobbyRoomTabbedPlayerList.updateBounds(lobbyRoomLeftPanel.width, lobbyRoomLeftPanel.height - 42); + Component.JOINED_PLAYER_COUNT_LABEL.setBounds(0, 0, Component.JOINED_PLAYERS_PANEL.width, Component.LABEL_HEIGHT); + Component.NAME_LABEL.setBounds(0, Component.LABEL_HEIGHT + 2, Component.JOINED_PLAYERS_PANEL.width - (4 + Component.LABEL_HEIGHT + 40), 18); + Component.RATING_LABEL.setBounds(Component.JOINED_PLAYERS_PANEL.width - Component.LABEL_HEIGHT - 40 - 2, Component.LABEL_HEIGHT + 2, 57, 18); + //noinspection SuspiciousNameCombination + Component.JOINED_PLAYERS_TABLE.setBounds(0, 22 + Component.LABEL_HEIGHT, Component.JOINED_PLAYERS_PANEL.width, -Component.LABEL_HEIGHT + (Component.JOINED_PLAYERS_PANEL.height - 2) - 20, Component.LABEL_HEIGHT); + Component.RETURN_TO_LOBBY_BUTTON.setBounds(0, lobbyRoomLeftPanel.height - 40, lobbyRoomLeftPanel.width, 40); + Component.GAME_OWNER_HEADING.setBounds(0, 0, Component.GAME_INFO_CONTAINER.width, 30); + Component.GAME_OPTIONS_CONTAINER.setBounds(0, 30, Component.GAME_INFO_CONTAINER.width, Component.GAME_INFO_CONTAINER.height - 30 - 42); + int var2 = 3 + GAMEOPT_CHOICES_COUNTS.length; + + if (isRated) { + --var2; + } + + int var3 = (Component.GAME_OPTIONS_CONTAINER.height + 2 + (var2 + 1) / 2 - 20) / (var2 + 1) - 2; + if (var3 > 30) { + var3 = 30; + } + + int var4 = -(var2 * (var3 + 2)) - 5 + (Component.GAME_OPTIONS_CONTAINER.height - 5); + if (var4 > 40) { + var4 = 40; + } + + Component.GAME_OPTIONS_HEADING.setBounds(5, 5, Component.GAME_OPTIONS_CONTAINER.width - 5 - 5, var4); + int var5 = 2 + var4 + 5; + + for (int var6 = 0; GAMEOPT_CHOICES_COUNTS.length + 4 > var6; ++var6) { + if (var6 != 3) { + int var8; + ActionButton var9; + final Component var13; + if (isRated && var6 == 0) { + var13 = Component.GAME_OPTIONS_LABELS[0]; + Component.GAME_OPTIONS_LABELS[0].height = 0; + var13.width = 0; + + for (var8 = 0; Component.GAME_OPTIONS_BUTTONS[var6].length > var8; ++var8) { + if (Component.GAME_OPTIONS_BUTTONS[var6][var8] != null) { + var9 = Component.GAME_OPTIONS_BUTTONS[var6][var8]; + Component.GAME_OPTIONS_BUTTONS[var6][var8].height = 0; + var9.width = 0; + } + } + } else { + final int var15; + Component.GAME_OPTIONS_LABELS[var6].setBounds(5, var5, 103, var3); + var8 = 110; + if (isRated) { + Component.GAME_OPTIONS_BUTTONS[var6][0].a370(var3, var5, 2, ClientLobbyRoom._qob, 38, var8); + var8 += 40; + } else if (Component.GAME_OPTIONS_BUTTONS[var6][0] != null) { + var9 = Component.GAME_OPTIONS_BUTTONS[var6][0]; + Component.GAME_OPTIONS_BUTTONS[var6][0].height = 0; + var9.width = 0; + } + + var15 = 2 + (Component.GAME_INFO_CONTAINER.width - var8 - 5); + final int var10 = Component.GAME_OPTIONS_BUTTONS[var6].length - 1; + + for (int var11 = 0; var11 < var10; ++var11) { + final int var12 = var11 * var15 / var10; + Component.GAME_OPTIONS_BUTTONS[var6][1 + var11].a370(var3, var5, 2, ClientLobbyRoom._qob, -var12 + ((1 + var11) * var15 / var10 - 2), var12 + var8); + } + + var5 += var3 + 2; + } + } + } + + invitePlayersDialog.setBounds(Drawing.width - 360 >> 1, 10, 360, Drawing.height - 10 - 120 - 4 - 10); + Component.INVITE_PLAYERS_LABEL.setBounds(0, 0, invitePlayersDialog.width, 24); + invitePlayersDialogContents.setBounds(0, 24, invitePlayersDialog.width, invitePlayersDialog.height - 24); + invitePlayersDialogContents.nineSliceSprites = Component.createGradientOutlineSprites(invitePlayersDialogContents.height, 11579568, 8421504, 1); + Component.INVITE_PLAYER_LIST_PANEL.setBounds(5, 5, invitePlayersDialogContents.width - 10, invitePlayersDialogContents.height - 2 - 10 - 24); + Component.CLOSE_BUTTON_2.setBounds((invitePlayersDialogContents.width - 80) / 2, invitePlayersDialogContents.height - 5 - 24, 80, 24); + d150p(); + } + + public static void d150p() { + Component.INVITE_PLAYER_LIST_HEADING_NAME.setBounds(0, 0, Component.INVITE_PLAYER_LIST_PANEL.width - (42 + Component.LABEL_HEIGHT + 2), 18); + Component.INVITE_PLAYER_LIST_HEADING_RATING.setBounds(Component.INVITE_PLAYER_LIST_PANEL.width - (17) - 40, 0, 57, 18); + //noinspection SuspiciousNameCombination + Component.INVITE_PLAYER_LIST_SCROLL_PANE.setBounds(0, 20, Component.INVITE_PLAYER_LIST_PANEL.width, Component.INVITE_PLAYER_LIST_PANEL.height - 20, Component.LABEL_HEIGHT); + } + + private static Sprite[] a113hl() { + Drawing.saveContext(); + final Sprite[] var1 = new Sprite[80]; + final Sprite var2 = new Sprite(240, 120); + + for (int var3 = 0; var3 < 80; ++var3) { + var2.installForDrawing(); + Drawing.clear(); + + for (int var4 = 0; var4 < 4; ++var4) { + final double var5 = (double) (80 * (3 + var4) + var3) * 6.283185307179586D; + final double var7 = Math.sin(var5 / (double) (80 * 4)); + final double var9 = Math.cos(var5 / (double) (80 * 4)); + final int var11 = (int) (12288.0D / (var9 + 3.0D)); + final int var12 = 1920 + (int) (var7 * 2400.0D / (3.0D + var9)); + final int var13 = (int) (1920.0D / (3.0D + var9)); + BEAKER.b669(BEAKER.offsetX << 3, BEAKER.offsetY << 3, var12, var13, 0, var11); + } + + var1[var3] = new Sprite(60, 30); + var1[var3].installForDrawing(); + var2.g093(); + } + + Drawing.restoreContext(); + return var1; + } + + private static void a641tvc(final LobbyPlayer var1, final ScrollPane var3, final int mouseX, final int mouseY) { + showContextMenu(var3, var1, var1.playerId, var1.playerName, var1.playerDisplayName, -1, null); + ContextMenu.openInstance.addPlayerItems(true); + ContextMenu.openInstance.a124(null, Channel.LOBBY); + ContextMenu.openInstance.b150(); + ContextMenu.openInstance.view.positionRelativeToTarget(mouseX, mouseY); + } + + private static void e423ec() { + ratedLobbyRoom = null; + unratedLobbyRoom = null; + justRecievedRoomDetailsFromServer = false; + if (LobbyPlayer.online != null) { + LobbyPlayer.online.clear(); + LobbyPlayer.online = null; + } + + LobbyPlayer.onlineMap = null; + if (ClientLobbyRoom.rooms != null) { + ClientLobbyRoom.rooms.clear(); + ClientLobbyRoom.rooms = null; + } + + ClientLobbyRoom.roomsMap = null; + if (LobbyPlayer.joinedPlayers != null) { + LobbyPlayer.joinedPlayers.clear(); + LobbyPlayer.joinedPlayers = null; + } + + LobbyPlayer.joinedPlayersMap = null; + if (LobbyPlayer.onlineMap != null) { + LobbyPlayer.onlineMap.clear(); + LobbyPlayer.onlineMap = null; + } + } + + private static void handleLobbyPacket() { + @MagicConstant(valuesFromClass = S2CPacket.LobbyAction.class) + final int action = s2cPacket.readUByte(); + if (action == S2CPacket.LobbyAction.YOU_LEFT_ROOM + || action == S2CPacket.LobbyAction.YOU_WERE_KICKED + || action == S2CPacket.LobbyAction.YOU_CREATED_RANKED_ROOM + || action == S2CPacket.LobbyAction.YOU_JOINED_RANKED_ROOM + || action == S2CPacket.LobbyAction.YOU_JOINED_ROOM) { + LobbyPlayer.joinedPlayers.clear(); + LobbyPlayer.joinedPlayersMap.clear(); + + for (final LobbyPlayer player : LobbyPlayer.onlineMap.values()) { + if (player.inviteSent || player.joinRequestReceived) { + player.inviteSent = false; + if (player.joinRequestReceived) { + --joinRequestCount; + player.joinRequestReceived = false; + } + LobbyPlayer.addOnline(player); + } + } + + if (action == S2CPacket.LobbyAction.YOU_WERE_KICKED && unratedLobbyRoom != null) { + playerWhoKickedYou = unratedLobbyRoom.ownerName; + } + + if (action == S2CPacket.LobbyAction.YOU_JOINED_ROOM) { + final int roomId = s2cPacket.readUShort(); + unratedLobbyRoom = new ClientLobbyRoom(roomId); + unratedLobbyRoom.initializeFromServer(s2cPacket, false); + cannotStartGameUntil = 0L; + } else { + unratedLobbyRoom = null; + } + + if (action == S2CPacket.LobbyAction.YOU_CREATED_RANKED_ROOM || action == S2CPacket.LobbyAction.YOU_JOINED_RANKED_ROOM) { + if (ratedLobbyRoom == null) { + ratedLobbyRoom = new ClientLobbyRoom(0); + } + } else { + ratedLobbyRoom = null; + } + + if (action == S2CPacket.LobbyAction.YOU_JOINED_RANKED_ROOM) { + justRecievedRoomDetailsFromServer = true; + for (int i = 0; i < playerSeatsFilledBitmap.length; ++i) { + playerSeatsFilledBitmap[i] = s2cPacket.readByte(); + } + + maxAiPlayersSelection = s2cPacket.readUByte(); + allowSpectateSelection = s2cPacket.readUByte(); + + for (int i = 0; i < gameoptChoicesBitmap.length; ++i) { + gameoptChoicesBitmap[i] = s2cPacket.readByte(); + } + } else { + justRecievedRoomDetailsFromServer = false; + } + } else if (action == S2CPacket.LobbyAction.PLAYER_ENTERED_LOBBY) { + final long playerId = s2cPacket.readLong(); + final String playerName = s2cPacket.readNullTerminatedString(); + final String previousDisplayName = s2cPacket.readNullTerminatedString(); + final String playerDisplayName = s2cPacket.readNullTerminatedString(); + LobbyPlayer player = LobbyPlayer.getOnline(playerId); + if (player == null) { + player = new LobbyPlayer(playerId, playerName, playerDisplayName); + LobbyPlayer.onlineMap.put(playerId, player); + } else if (!previousDisplayName.isEmpty()) { + player.setName(playerName, playerDisplayName); + } + + player.joinedAt = PseudoMonotonicClock.currentTimeMillis() - (long) s2cPacket.readInt(); + player.rating = s2cPacket.readUShort(); + player.ratedGameCount = s2cPacket.readVariableInt() >> 1; + player.crown = s2cPacket.readUByte(); + player.unlockedOptionsBitmap = s2cPacket.readUByte(); + LobbyPlayer.addOnline(player); + } else if (action == S2CPacket.LobbyAction.PLAYER_LEFT_LOBBY) { + final long playerId = s2cPacket.readLong(); + final int reason = s2cPacket.readUByte(); + final LobbyPlayer player = LobbyPlayer.getOnline(playerId); + if (player != null) { + if (player.joinRequestReceived) { + --joinRequestCount; + player.joinRequestReceived = false; + } + + if (reason == 0) { + LobbyPlayer.online.remove(player); + } else { + player.status = reason; + player.statusTimer = STATUS_MESSAGE_TIMEOUT_DURATION; + } + + LobbyPlayer.onlineMap.remove(playerId); + } + } else if (action == S2CPacket.LobbyAction.REMOVE_ALL_JOIN_REQUESTS) { + LobbyPlayer.online.clear(); + LobbyPlayer.onlineMap.clear(); + joinRequestCount = 0; + } else if (action == S2CPacket.LobbyAction.ADD_ROOM) { + final int roomId = s2cPacket.readUShort(); + ClientLobbyRoom room = ClientLobbyRoom.roomsMap.get(roomId); + if (room == null) { + room = new ClientLobbyRoom(roomId); + ClientLobbyRoom.roomsMap.put(roomId, room); + } + room.initializeFromServer(s2cPacket, true); + ClientLobbyRoom.add(room); + } else if (action == S2CPacket.LobbyAction.REMOVE_ROOM) { + final int roomId = s2cPacket.readUShort(); + final int reason = s2cPacket.readUByte(); + final ClientLobbyRoom room = ClientLobbyRoom.roomsMap.get(roomId); + if (room != null) { + if (reason == 0) { + ClientLobbyRoom.rooms.remove(room); + } else { + room.status = reason; + room.statusTimer = STATUS_MESSAGE_TIMEOUT_DURATION; + } + ClientLobbyRoom.roomsMap.remove(roomId); + } + } else if (action == S2CPacket.LobbyAction.REMOVE_ALL_ROOMS) { + ClientLobbyRoom.rooms.clear(); + ClientLobbyRoom.roomsMap.clear(); + } else if (action == S2CPacket.LobbyAction.YOU_ARE_INVITED || action == S2CPacket.LobbyAction.YOU_SENT_JOIN_REQUEST) { + final int roomId = s2cPacket.readUShort(); + final ClientLobbyRoom room = ClientLobbyRoom.roomsMap.get(roomId); + if (room != null) { + if (action == S2CPacket.LobbyAction.YOU_ARE_INVITED) { + room.youAreInvited = true; + } else { + room.submittedJoinRequest = true; + } + ClientLobbyRoom.add(room); + } + } else if (action == S2CPacket.LobbyAction.ROOM_STATUS) { + final int roomId = s2cPacket.readUShort(); + final int status = s2cPacket.readUByte(); + final ClientLobbyRoom room = ClientLobbyRoom.roomsMap.get(roomId); + if (room != null) { + room.submittedJoinRequest = false; + room.youAreInvited = false; + if (status != 0) { + room.status = status; + room.statusTimer = STATUS_MESSAGE_TIMEOUT_DURATION; + } + ClientLobbyRoom.add(room); + } + } else if (action == S2CPacket.LobbyAction.ADD_PLAYER_INVITE || action == S2CPacket.LobbyAction.ADD_PLAYER_JOIN_REQUEST) { + final long playerId = s2cPacket.readLong(); + final LobbyPlayer player = LobbyPlayer.getOnline(playerId); + if (player != null) { + if (action == S2CPacket.LobbyAction.ADD_PLAYER_INVITE) { + player.inviteSent = true; + } else if (!player.joinRequestReceived) { + ++joinRequestCount; + player.joinRequestReceived = true; + } + LobbyPlayer.addOnline(player); + } + } else if (action == S2CPacket.LobbyAction.REMOVE_PLAYER_INVITE || action == S2CPacket.LobbyAction.REMOVE_PLAYER_JOIN_REQUEST) { + final long playerId = s2cPacket.readLong(); + final int reason = s2cPacket.readUByte(); + final LobbyPlayer player = LobbyPlayer.getOnline(playerId); + if (player != null) { + if (action == S2CPacket.LobbyAction.REMOVE_PLAYER_INVITE) { + player.inviteSent = false; + } else if (player.joinRequestReceived) { + --joinRequestCount; + player.joinRequestReceived = false; + } + if (reason != 0) { + player.status = reason; + player.statusTimer = STATUS_MESSAGE_TIMEOUT_DURATION; + } + LobbyPlayer.addOnline(player); + } + } else if (action == S2CPacket.LobbyAction.PLAYER_JOINED_ROOM) { + final long playerId = s2cPacket.readLong(); + final String playerName = s2cPacket.readNullTerminatedString(); + final String playerDisplayName = s2cPacket.readNullTerminatedString(); + LobbyPlayer player = LobbyPlayer.getJoined(playerId); + if (player == null) { + player = new LobbyPlayer(playerId, playerName, playerDisplayName); + LobbyPlayer.joinedPlayersMap.put(playerId, player); + ++unratedLobbyRoom.joinedPlayerCount; + } + + player.rating = s2cPacket.readUShort(); + player.ratedGameCount = s2cPacket.readVariableInt() >> 1; + player.crown = s2cPacket.readUByte(); + player.unlockedOptionsBitmap = s2cPacket.readUByte(); + LobbyPlayer.joinedPlayers.add(player); + } else if (action == S2CPacket.LobbyAction.PLAYER_LEFT_ROOM) { + final long playerId = s2cPacket.readLong(); + final int reason = s2cPacket.readUByte(); + final LobbyPlayer player = LobbyPlayer.getJoined(playerId); + if (player != null) { + if (reason == 0) { + LobbyPlayer.joinedPlayers.remove(player); + } else { + player.status = reason; + player.statusTimer = STATUS_MESSAGE_TIMEOUT_DURATION; + } + LobbyPlayer.joinedPlayersMap.remove(playerId); + --unratedLobbyRoom.joinedPlayerCount; + } + } else if (action == S2CPacket.LobbyAction.ROOM_INFO) { + unratedLobbyRoom.initializeFromServer(s2cPacket, false); + } else if (action == S2CPacket.LobbyAction.GAME_OPTIONS_CHANGED) { + final int cannotStartTimeout = s2cPacket.readUShort(); + if (cannotStartTimeout == 0) { + cannotStartGameUntil = 0L; + } else { + cannotStartGameUntil = PseudoMonotonicClock.currentTimeMillis() + (long) cannotStartTimeout; + } + } else if (action == S2CPacket.LobbyAction.RATING) { + playerRating = s2cPacket.readUShort(); + s2cPacket.readVariableInt(); + } else if (action == S2CPacket.LobbyAction.PLAYER_ID) { + localPlayerId = s2cPacket.readLong(); + } else { + clientError(null, "L1: " + a738w()); + shutdownServerConnection(); + } + } + + public static boolean isCurrentRoomOwner() { + return unratedLobbyRoom.ownerId == localPlayerId; + } + + public static boolean isPopupOpen() { + return ContextMenu.openInstance != null + || AddOrRemovePlayerPopup.openInstance != null + || ReportAbuseDialog.openInstance != null + || QuickChatHelpPanel.openInstance != null + || isQuickChatOpen; + } + + private static boolean processQuickChatKeyInput() { + if (lastTypedKeyCode == KeyState.Code.ESCAPE) { + closeQuickChatIfOpen(); + return true; + } else if (lastTypedKeyCode == KeyState.Code.HOME) { + _dmrh.close(); + return true; + } else { + return _dmrh != null && _dmrh.a777(); + } + } + + public static void a827jo(final MusicTrack track, final int var3, final boolean var2) { + Sounds.musicTn.a180(track, var3, !var2); + } + + public static int randomIntBounded(final int var0) { + return randomIntBounded(globalRandom, var0); + } + + public static int randomIntBounded(final Random rand, final int end) { + if (end <= 0) { + throw new IllegalArgumentException(); + } else if (end == (-end & end)) { + return (int) (((long) end * ((long) rand.nextInt() & 0xffffffffL)) >> 32); + } else { + final int var2 = -((int) (4294967296L % (long) end)) - Integer.MIN_VALUE; + + int var3; + do { + var3 = rand.nextInt(); + } while (var3 >= var2); + + return a313jf(end, var3); + } + } + + private static GetProfileRequest loadProfile() { + final GetProfileRequest response = new GetProfileRequest(); + getProfileResponses.add(response); + C2SPacket.sendProfileGet(); + return response; + } + + private static void discardTypedChatMessage() { + typedChatMessage.setLength(0); + currentChatChannel = Channel.LOBBY; + } + + private static void a430mj(final boolean var1) { + if (ClientLobbyRoom.currentTooltip != null) { + a407dk(ClientLobbyRoom.currentTooltip); + } + + if (ContextMenu.openInstance != null) { + ContextMenu.openInstance.a430(var1); + } + + a893r(var1); + if (ReportAbuseDialog.openInstance != null) { + ReportAbuseDialog.openInstance.b540(var1); + } + + a540ho(var1); + } + + private static void a430se() { + for (final RankingsRequest request : Menu.rankingsRequests) { + C2SPacket.a970uf(request); + } + } + + public static String a034ih(final CharSequence var0) { + String var1 = a019pd(UserIdLoginCredentials.encodeUsername(var0)); + if (var1 == null) { + var1 = ""; + } + + return var1; + } + + public static int randomIntBounded(final int min, final int max) { + return min + randomIntBounded(globalRandom, max - min + 1); + } + + public static void a150wp() { + //noinspection InlineNestedElse + if (ClientGameSession.playSession.isUnrated) { + if (ClientGameSession.playSession.gameState.isPlayerOfferingRematch(ClientGameSession.playSession.localPlayerIndex)) { + MENU_ITEM_LABELS[13] = StringConstants.MP_CANCEL_REMATCH_UNRATED; + } else if (ClientGameSession.playSession.gameState.isAnyoneOfferingRematch()) { + MENU_ITEM_LABELS[13] = StringConstants.MP_ACCEPT_REMATCH_UNRATED; + } else if (ClientGameSession.playSession.haveAllOtherPlayersLeft()) { + MENU_ITEM_LABELS[13] = StringConstants.MP_REMATCH_NEW_GAME_UNRATED; + } else { + MENU_ITEM_LABELS[13] = StringConstants.MP_OFFER_REMATCH_UNRATED; + } + } else { + if (ClientGameSession.playSession.gameState.isPlayerOfferingRematch(ClientGameSession.playSession.localPlayerIndex)) { + MENU_ITEM_LABELS[13] = StringConstants.MP_CANCEL_REMATCH; + } else if (ClientGameSession.playSession.gameState.isAnyoneOfferingRematch()) { + MENU_ITEM_LABELS[13] = StringConstants.MP_ACCEPT_REMATCH; + } else if (ClientGameSession.playSession.haveAllOtherPlayersLeft()) { + MENU_ITEM_LABELS[13] = StringConstants.MP_REMATCH_NEW_GAME; + } else { + MENU_ITEM_LABELS[13] = StringConstants.MP_OFFER_REMATCH; + } + } + } + + private static void layoutLobbyRoomPanels(final int transitionCounter) { + final int var1 = (Component.lastLayoutWidth - SCREEN_WIDTH) / 2; + final int var2 = 400; + final int var3 = var2 - transitionCounter * transitionCounter; + lobbyRoomLeftPanel.setBounds(var1 - 199 * var3 / var2, 90, 199, Drawing.height - 120 - 94); + Component.GAME_INFO_CONTAINER.setBounds(438 * var3 / var2 + var1 + 202, 0, 438, Drawing.height - 124); + } + + private static void a630gr(final boolean var0) { + if (var0) { + Drawing.fillRect(0, 0, Drawing.width, Drawing.height, 0, 192); + } else { + Drawing.clear(); + } + CommonUI.draw(); + } + + private static void a790cq(final int textColor, final String var1, final String message, final int var3) { + chatMessageLabel.textColor = textColor; + chatMessageLabel.label = message; + chatMessageLabel._u = var1; + chatMessageLabel.width += Component._cgC.width; + Component._cgC.x += Component._cgC.width; + Component._cgC.width = var3; + chatMessageLabel.width -= Component._cgC.width; + Component._cgC.x -= Component._cgC.width; + } + + private static void closeQuickChatIfOpen() { + if (isQuickChatOpen) { + closeQuickChat(); + } + } + + private static void a893ml(final boolean var0) { + Component._tgc.b540(var0); + final DobToEnableChatForm var1 = DobToEnableChatForm.instance; + if (var1 != null) { + var1.drawRoot(Component._tgc.x2, Component._tgc.y2); + } + + } + + private static void a877rad(final boolean var0) { + _faX.b540(var0); + if (ClientLobbyRoom.currentTooltip != null) { + a407dk(ClientLobbyRoom.currentTooltip); + } + } + + private static void a407dk(final String var0) { + final int var1 = mouseX; + final int var2 = mouseY; + final int var3 = Component.LABEL.font.breakLines(var0, 500); + final int var5 = Component.LABEL.font.measureParagraphWidth(var0, 500) + 6; + final int var6 = 2 + var3 * Component.LABEL_HEIGHT; + final int var7 = PopupMenu.positionPopupX(var1, 12, var5); + final int var8 = PopupMenu.positionPopupY(var2, 20, var6); + Drawing.strokeRectangle(var7, var8, var5, var6, 0); + Drawing.fillRect(1 + var7, 1 + var8, var5 - 2, var6 - 2, 16777088); + Component.LABEL.font.drawParagraph(var0, var7 + 3, Component._si + (1 + var8 - Component.LABEL.font.ascent), 500, 1000, 0, Font.HorizontalAlignment.LEFT, Font.VerticalAlignment.TOP, Component.LABEL_HEIGHT); + } + + private static void tickLobbyListStatuses() { + for (final Iterator it = LobbyPlayer.online.iterator(); it.hasNext(); ) { + final LobbyPlayer player = it.next(); + if (player.statusTimer > 0) { + --player.statusTimer; + if (player.statusTimer == 0) { + player.status = 0; + if (!player.isInMap()) { + it.remove(); + } + } + } + } + + for (final Iterator it = ClientLobbyRoom.rooms.iterator(); it.hasNext(); ) { + final ClientLobbyRoom room = it.next(); + if (room.statusTimer > 0) { + --room.statusTimer; + if (room.statusTimer == 0) { + room.status = 0; + if (!room.isInMap()) { + it.remove(); + } + } + } + } + + for (final Iterator it = LobbyPlayer.joinedPlayers.iterator(); it.hasNext(); ) { + final LobbyPlayer player = it.next(); + if (player.statusTimer > 0) { + --player.statusTimer; + if (player.statusTimer == 0) { + player.status = 0; + if (!player.isInMap()) { + it.remove(); + } + } + } + } + } + + private static int a776wd(final int var0, final int var1) { + if (var1 < 2) { + return var0 < 5 ? 0 : 1; + } else { + return 2; + } + } + + private static void a326ts(int var0, int var2) { + var0 += 30; + var2 += 30; + Menu.drawShine(-var0 + SCREEN_WIDTH >> 1, -var2 + SCREEN_HEIGHT >> 1, var0, var2); + } + + private static void tickIgnoreList(final boolean mouseStill, final int mouseWheelRotation) { + final boolean var3 = Component.IGNORE_LIST.scrollPane.processScrollInput(mouseStill, Component.IGNORE_LIST.scrollPane == currentContextMenuParent, 2 + Component.LABEL_HEIGHT, mouseWheelRotation * (Component.LABEL_HEIGHT + 2) * 3); + final List var4 = Component.IGNORE_LIST.entries.children; + if (PlayerListEntry.serverStatus == PlayerListEntry.ServerStatus.LOADED || PlayerListEntry.serverStatus == PlayerListEntry.ServerStatus.LOADING) { + Component.IGNORE_LIST.scrollPane.viewport.label = null; + Component.IGNORE_LIST.enabled = true; + PlayerListEntry var5 = null; + + for (final PlayerListEntry var6 : var4) { + boolean var7 = false; + if (var6.children == null) { + var6.playerNameLabel = new Component<>(Component.UNSELECTED_LABEL_DARK_2); + var6.addChild(var6.playerNameLabel); + var6.displayNameChangedIcon = new Component<>(Component.UNSELECTED_LABEL_DARK_2); + var6.addChild(var6.displayNameChangedIcon); + var7 = true; + var6.recursivelySet_H(); + } + + var6.width = Component.IGNORE_LIST.entries.width; + var6.playerNameLabel.setBounds(0, 0, var6.width, Component.LABEL_HEIGHT); + boolean var8 = false; + if (var6.previousDisplayName != null && !var6.previousDisplayName.equals("")) { + var6.displayNameChangedIcon.mouseOverTextColor = 16737894; + var6.displayNameChangedIcon.sprite = Component.DISPLAY_NAME_CHANGED; + var8 = true; + var6.displayNameChangedIcon.setBounds(0, 0, 3 + Component.DISPLAY_NAME_CHANGED.offsetX, Component.LABEL_HEIGHT); + } + + int var9 = 0; + int var10 = var6.width; + if (var8) { + var9 = Component.DISPLAY_NAME_CHANGED.offsetX + 3; + var10 -= var9; + } + + var6.playerNameLabel.label = var10 <= 0 ? var6.playerDisplayName : var6.playerNameLabel.font.truncateWithEllipsisToFit(var6.playerDisplayName, var10); + assert var6.playerNameLabel.label != null; + final boolean var11 = !var6.playerNameLabel.label.equals(var6.playerDisplayName); + var6.playerNameLabel.setBounds(var9, 0, var10, Component.LABEL_HEIGHT); + if (!var3) { + var6._gb = Component.LABEL_HEIGHT - var6.height; + } + + if (var7) { + Component.IGNORE_LIST.entries.placeAfter(var5, var6); + } + + if (var6.displayNameChangedIcon != null && var6.displayNameChangedIcon.isMouseOverTarget) { + ClientLobbyRoom.currentTooltip = var6.previousDisplayName; + } else if (var6.playerNameLabel.isMouseOverTarget && var11) { + ClientLobbyRoom.currentTooltip = var6.playerDisplayName; + } + + var5 = var6; + if (var6.clickButton != MouseState.Button.NONE) { + showContextMenu(Component.IGNORE_LIST.scrollPane, var6, 0L, var6.playerName, var6.playerDisplayName, -1, null); + final ContextMenu var12 = ContextMenu.openInstance; + final String var13 = StringConstants.MU_LOBBY_NAME_RM; + var12.view.addItem(var13, ContextMenu.ClickAction.REMOVE_IGNORE); + final ContextMenu m = ContextMenu.openInstance; + final int var15 = mousePressX; + final int var14 = mousePressY; + m.view.positionRelativeToTarget(var15, var14); + } + } + + if (Component.IGNORE_LIST.addButton.clickButton != MouseState.Button.NONE) { + AddOrRemovePlayerPopup.openInstance = new AddOrRemovePlayerPopup(Component.IGNORE_LIST.addButton.x2, Component.IGNORE_LIST.addButton.y2, Component.IGNORE_LIST.addButton.width, Component.IGNORE_LIST.addButton.height, StringConstants.ENTER_IGNORE_ADD, Component.POPUP, Component.LABEL, Component.LABEL); + AddOrRemovePlayerPopup.action = AddOrRemovePlayerPopup.Action.ADD_IGNORE; + } + + if (Component.IGNORE_LIST.removeButton.clickButton != MouseState.Button.NONE) { + AddOrRemovePlayerPopup.openInstance = new AddOrRemovePlayerPopup(Component.IGNORE_LIST.removeButton.x2, Component.IGNORE_LIST.removeButton.y2, Component.IGNORE_LIST.removeButton.width, Component.IGNORE_LIST.removeButton.height, StringConstants.ENTER_IGNORE_DEL, Component.POPUP, Component.LABEL, Component.LABEL); + AddOrRemovePlayerPopup.action = AddOrRemovePlayerPopup.Action.REMOVE_IGNORE; + } + } else { + Component.IGNORE_LIST.enabled = false; + Component.IGNORE_LIST.scrollPane.viewport.label = StringConstants.LOADING; + crunch(Component.IGNORE_LIST.entries); + } + + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public static boolean isComposingChatMessageTo(final String playerName) { + if (isChatboxSelected) { + return currentChatChannel == Channel.PRIVATE + && ContextMenu.normalizedRecipientPlayerName != null + && ContextMenu.normalizedRecipientPlayerName.equals(Strings.normalize(playerName)); + } else { + return false; + } + } + + private static void a487er() { + Menu._hgt = Menu.FONT.measureLineWidth(MENU_ITEM_LABELS[21]); + final int var0 = Menu.FONT.measureLineWidth(MENU_ITEM_LABELS[22]); + if (var0 > Menu._hgt) { + Menu._hgt = var0; + } + + } + + private static void b150lc() { + if (isQuickChatOpen) { + Drawing.h115(Drawing.left, Drawing.top, -Drawing.left + Drawing.right, -Drawing.top + Drawing.bottom); + Component._uaf.b540(false); + } + + } + + public static void saveProfile() { + if (!isAnonymous) { + if (GameUI.currentSettings != -1 && GameUI.currentSettings != GameUI.lastSavedSettings) { + final SetProfileRequest request = new SetProfileRequest(new byte[]{0, (byte) GameUI.currentSettings}); + profileSetRequests.add(request); + C2SPacket.sendProfileSet(request); + GameUI.lastSavedSettings = GameUI.currentSettings; + } + } + } + + private static String a614hg(final ChatMessage var1) { + String var2 = null; + if (var1.senderDisplayName != null) { + var2 = var1.senderDisplayName; + if (var1._c == 1) { + var2 = "" + var2; + } + + if (var1._c == 2) { + var2 = "" + var2; + } + } + + String var3 = ""; + if (var1.channel != Channel.PRIVATE) { + if (var1.channel == Channel.LOBBY) { + var3 = "[" + StringConstants.MU_CHAT_LOBBY + "] "; + } + + if (var1.channel == Channel.ROOM) { + var3 = "[" + Strings.format(StringConstants.XS_GAME, var1._o) + "] "; + } + + if (var1.channel == Channel.CHANNEL_4) { + var3 = "[#" + var1._o + "] "; + } + + if (!var1._h) { + var3 = var3 + var2 + ": "; + } + } else if (!var1._h) { + if (var1._l == 0 && var1._e == 0) { + var3 = Strings.format(StringConstants.PRIVATE_QUICK_CHAT_TO_X, var2); + } else { + var3 = Strings.format(StringConstants.PRIVATE_QUICK_CHAT_FROM_X, var2); + } + } + + return var3; + } + + private static void a540ho(final boolean var0) { + if (QuickChatHelpPanel.openInstance != null) { + Drawing.h115(Drawing.left, Drawing.top, Drawing.right - Drawing.left, -Drawing.top + Drawing.bottom); + QuickChatHelpPanel.openInstance.b540(var0); + } + } + + private static int a137sa() { + return Menu._hoa - Menu._dbf; + } + + private static int a313jf(final int var0, final int var1) { + final int var3 = var0 - 1 & var1 >> 31; + return (var1 + (var1 >>> 31)) % var0 + var3; + } + + private static void a681ks(final ChatMessage var0) { + showContextMenu(null, var0.component, var0.senderId, var0.senderName, var0.senderDisplayName, var0.channel != Channel.ROOM ? 0 : var0._g, var0.channel); + ContextMenu var2; + String var3; + if (var0.channel == Channel.LOBBY && !a427ha() && unratedLobbyRoom == null && ratedLobbyRoom == null) { + if (!canOnlyQuickChat) { + var2 = ContextMenu.openInstance; + var3 = StringConstants.MESSAGE_LOBBY; + var2.view.addItem(var3, ContextMenu.ClickAction.SEND_CHANNEL_MESSAGE); + } + + var2 = ContextMenu.openInstance; + var3 = StringConstants.QUICKCHAT_LOBBY; + var2.view.addItem(var3, ContextMenu.ClickAction.SEND_CHANNEL_MESSAGE_QC); + } + + if (var0.channel == Channel.ROOM && !a427ha() && unratedLobbyRoom != null && var0._g == unratedLobbyRoom.roomId) { + if (!canOnlyQuickChat) { + var2 = ContextMenu.openInstance; + var3 = StringConstants.MESSAGE_GAME; + var2.view.addItem(var3, ContextMenu.ClickAction.SEND_CHANNEL_MESSAGE); + } + + var2 = ContextMenu.openInstance; + var3 = StringConstants.QUICKCHAT_GAME; + var2.view.addItem(var3, ContextMenu.ClickAction.SEND_CHANNEL_MESSAGE_QC); + } + + ContextMenu.openInstance.a487(); + ContextMenu.openInstance.addPlayerItems(false); + ContextMenu.openInstance.a124(var0._f, var0.channel); + ContextMenu.openInstance.b150(); + ContextMenu.openInstance.a408(var0); + var2 = ContextMenu.openInstance; + var2.view.positionRelativeToTarget(mousePressX, mousePressY); + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + private static boolean a427ha() { + return isChatboxSelected && currentChatChannel == Channel.LOBBY; + } + + private static void a893r(final boolean var0) { + if (AddOrRemovePlayerPopup.openInstance != null) { + AddOrRemovePlayerPopup.openInstance.b540(var0); + } + } + + static @Nullable ChatMessage getLastChatMessage() { + return chatMessageCount == 0 ? null + : chatMessages[chatMessageCount - 1]; + } + + @Override + public void shutdown() { + if (Sounds.musicChannel != null) { + Sounds.musicChannel.shutdown(); + } + + if (Sounds.soundsChannel != null) { + Sounds.soundsChannel.shutdown(); + } + + removeFocusLossDetectingCanvas(); + if (canvas != null) { + detachFromCanvas(canvas); + } + + if (JagexApplet.pageSource != null) { + JagexApplet.pageSource.close(); + } + + if (CacheWorker.instance != null) { + CacheWorker.instance.close(); + } + + if (ResourceLoader.bufferedCacheDat2 != null) { + try { + ResourceLoader.bufferedCacheDat2.close(); + } catch (final IOException var4) { + } + } + + if (ResourceLoader.bufferedCacheFiles != null) { + for (int var1 = 0; var1 < ResourceLoader.bufferedCacheFiles.length; ++var1) { + if (ResourceLoader.bufferedCacheFiles[var1] != null) { + try { + ResourceLoader.bufferedCacheFiles[var1].close(); + } catch (final IOException var3) { + } + } + } + } + + if (JagexApplet.serverConnection1 != null && (loginState == LoginState.LOGIN_REQUEST_SENT || loginState == LoginState.LOGIN_REQUEST_SUCCESSFUL || loginState == LoginState.LOGGED_IN)) { + C2SPacket.goodbye(); + JagexApplet.flushC2sPacket(0); + } + + JagexApplet.shutdownServerConnection(); + } + + @Override + public void initialize() { + super.initialize(); + + final h_ musicTn = new h_(); + musicTn._u.initialize(); + musicTn._r.initialize(); + musicTn._u.setVolume(Sounds.MAX_VOLUME); + musicTn._r.setVolume(Sounds.MAX_VOLUME); + + Sounds.musicChannel = createAudioChannel(0, SampledAudioChannel.SAMPLES_PER_SECOND); + Sounds.soundsChannel = createAudioChannel(1, 1102); + + Sounds.soundsTn = new vk_(); + Sounds.soundsChannel.setSource(Sounds.soundsTn); + Sounds.musicTn = musicTn; + Sounds.musicTn.setVolume(Sounds.musicVolume); + Sounds.musicChannel.setSource(Sounds.musicTn); + + renderQuality = RenderQuality.high(); + Menu.gameOptions = GameOptions.STREAMLINED_GAME_OPTIONS; + _flh = 20; + } + + @Override + public void tick() { + ticksSinceLastMouseEventAtStartOfTick = MouseState.ticksSinceLastMouseEvent; + tickSomethingThatSeemsRelatedToAudio(); + if (fullScreenCanvas != null && fullScreenCanvas.focusWasLost) { + removeFocusLossDetectingCanvas(); + if (Menu.isFullscreenDialogOpen) { + Menu.showFullscreenDialog(Menu.FullscreenDialog.LOST_FOCUS, false); + } + } + + this.a540(fullScreenCanvas != null); + + ++currentTick; + if (!isConnectedAndLoaded()) { + this.j423(); + if (!isConnectedAndLoaded()) { + return; + } + } + + final boolean var2 = this.tick_1(); + //noinspection InlineNestedElse + if (var2) { + if (_ebb < 128 && (_ebb += _jlU) > 128) { + _ebb = 128; + } + } else { + if (_ebb > 0 && (_ebb -= _jlU) < 0) { + _ebb = 0; + } + } + + while (recieveS2cPacket()) { + if (currentS2cPacketType == Type.ERROR) { + switchMenus(); + _mdQ = false; + Menu.nextMenu = Menu.Id.ERROR; + networkErrorMessage = JagexApplet.s2cPacket.readNullTerminatedString(); + } else if (currentS2cPacketType == Type.ENTER_MP) { + switchMenus(); + a969be(); + PlayerListEntry.initialize(Objects.requireNonNull(Component.FRIEND_LIST.entries), Component.IGNORE_LIST.entries); + inLobbyBrowser = true; + _mdQ = false; + Menu.nextMenu = Menu.Id.LOBBY; + } else if (currentS2cPacketType == Type.LEAVE_MP) { + if (inLobbyBrowser) { + switchMenus(); + a423ppi(); + clearChatMessages(); + Menu.switchTo(Menu.Id.MAIN, 0, false); + inLobbyBrowser = false; + _lgb = true; + _tli = false; + spectatingGame = false; + playingGame = false; + leavingLobby = true; + b150nj(); + } + + _isa = false; + _mdQ = false; + } else if (currentS2cPacketType == Type.LOBBY && inLobbyBrowser) { + handleLobbyPacket(); + } else if (currentS2cPacketType == Type.ACHIEVEMENTS_UNLOCKED) { + if (areAchievementsInitialized) { + final int achievementsBitmap = JagexApplet.s2cPacket.readInt(); + final int newAchievementsBitmap = achievementsBitmap & ~Menu.unlockedAchievementsBitmap; + for (int i = 0; i < StringConstants.ACHIEVEMENT_NAMES.length; ++i) { + if ((newAchievementsBitmap & (1 << i)) != 0) { + this.achievementNotifications.add(new AchievementNotification(i)); + } + } + Menu.unlockedAchievementsBitmap |= newAchievementsBitmap; + } + } else if (currentS2cPacketType == Type.ENTER_GAME) { + switchMenus(); + final int turnLengthIndex = JagexApplet.s2cPacket.readUByte(); + final GameOptions options = GameOptions.read(s2cPacket); + final GameState.GameType gameType = GameState.GameType.decode(JagexApplet.s2cPacket.readByte()); + final boolean isUnrated = JagexApplet.s2cPacket.readUByte() != 0; + final byte localPlayerIndex = JagexApplet.s2cPacket.readByte(); + final boolean hasLocalPlayer = localPlayerIndex >= 0; + final String[] playerNames = new String[JagexApplet.s2cPacket.readUByte()]; + Arrays.setAll(playerNames, i -> JagexApplet.s2cPacket.readNullBracketedString()); + + final ClientGameSession prevSession = hasLocalPlayer ? ClientGameSession.playSession : ClientGameSession.spectateSession; + final GameUI ui = prevSession != null ? prevSession.ui : null; + final ClientGameSession session = new ClientGameSession(true, false, turnLengthIndex, options, gameType, playerNames, localPlayerIndex, isUnrated, ui); + boolean var14 = true; + if (session.localPlayer != null) { + var14 = JagexApplet.s2cPacket.readUByte() == 1; + } + + try { + session.gameState.readMap(s2cPacket, session.localPlayer); + } catch (final MapGenerationFailure var16) { + JagexApplet.clientError(var16, "Map Generation failed when receiving initial game state from server."); + JagexApplet.shutdownServerConnection(); + continue; + } catch (final TannhauserUnconnectedException var17) { + JagexApplet.clientError(var17, "Gamestate received from server is invalid."); + JagexApplet.shutdownServerConnection(); + continue; + } +// catch (final Exception var18) { +// JagexApplet.clientError(var18, "Error receiving gamestate from server."); +// JagexApplet.shutdownServerConnection(); +// continue; +// } + + session.initialize(); + session.readyToEndTurn = var14; + if (hasLocalPlayer) { + playingGame = true; + ClientGameSession.playSession = session; + ClientGameSession.updateDrawOfferMenuItem(); + a150wp(); + a874b(Component.LABEL, Component.TAB_ACTIVE); + } else { + spectatingGame = true; + ClientGameSession.spectateSession = session; + } + + Menu.switchTo(Menu.Id.GAME, 0, false); + GameUI._gen = false; + _tli = true; + _isa = false; + } else if (currentS2cPacketType == Type.LEAVE_GAME) { + if (playingGame || spectatingGame) { + switchMenus(); + if (playingGame) { + ClientGameSession.playSession.handlePlayerLeft(false); + } + + _lgb = true; + playingGame = false; + Menu.nextMenu = Menu.Id.LOBBY; + _tli = false; + spectatingGame = false; + GameUI._gen = true; + b150nj(); + } + + _isa = false; + } else { + ClientGameSession var4 = null; + if (playingGame) { + var4 = ClientGameSession.playSession; + } else if (spectatingGame) { + var4 = ClientGameSession.spectateSession; + } + + if (var4 == null || !var4.handlePacket(currentS2cPacketType, s2cPacket, nextS2cPacketLen)) { + this.mgsPacketHandler(); + } + } + } + + JagexApplet.flushC2sPacket(0); + if (achievementRequest != null && achievementRequest.completed) { + Menu.unlockedAchievementsBitmap |= achievementRequest.unlockedAchievementsBitmap; + Menu.areAchievementsOffline = achievementRequest.areAchievementsOffline; + achievementRequest = null; + areAchievementsInitialized = true; + } + + if (Menu.currentMenu == Menu.Id.LOBBY && Menu.nextMenu != Menu.Id.GAME) { + GameUI._gen = true; + } + + final boolean shouldForceDisconnection = + (debugModeEnabled || (ClientGameSession.playSession != null && ClientGameSession.playSession.desynced) || (ClientGameSession.spectateSession != null && ClientGameSession.spectateSession.desynced)) + && JagexApplet.keysDown[KeyState.Code.CONTROL] && JagexApplet.keysDown[KeyState.Code.FORWARD_SLASH]; + if (shouldForceDisconnection) { + JagexApplet.shutdownServerConnection(); + } + + if (JagexApplet.f154jc()) { + @MagicConstant(valuesFromClass = CommonUI.LoginResult.class) + final int loginResult = this.tickReconnecting(); + if (loginResult == CommonUI.LoginResult.SUCCESS || loginResult == CommonUI.LoginResult.R1) { + a366vs(); + a430se(); + a093oq(); + ReflectionRequest.pending = new ArrayDeque<>(); + if (loginResult == CommonUI.LoginResult.R1) { + _mdQ = true; + _isa = true; + } else { + if (inLobbyBrowser) { + _lgb = true; + _tli = false; + leavingLobby = true; + if (playingGame) { + networkErrorMessage = StringConstants.TEXT_REMOVED_FROM_GAME; + Menu.switchTo(Menu.Id.ERROR, 0, false); + } else { + Menu.switchTo(Menu.Id.MAIN, 0, false); + } + + switchMenus(); + Menu.menus[Menu.currentMenu].a126(false); + spectatingGame = false; + playingGame = false; + inLobbyBrowser = false; + b150nj(); + } + + _mdQ = false; + _isa = false; + } + } + + if (loginResult == CommonUI.LoginResult.R2 || shouldForceDisconnection || inLobbyBrowser || _mdQ || _isa) { + CommonUI.handleServerDisconnect(); + } + } + } + + private boolean tick_1() { + if (!isFullyLoaded) { + CommonUI.tick(); + if (this.loadNext()) { + isFullyLoaded = true; + } + return false; + } + if (!isProfileInitialized()) { + tickLoadProfile(); + return false; + } + if (!menuInitialized) { + if (!isAnonymous) { + Menu.updateAvailableMenuItems(); + } + menuInitialized = true; + return false; + } + + if (Menu.isFullscreenDialogOpen) { + if (_jbg == EnumJbg.C0) { + final Menu.DialogOption var3 = d474cq(); + if (var3 == Menu.DialogOption.ACCEPT) { + removeFocusLossDetectingCanvas(); + } else if (var3 == Menu.DialogOption.TRY_AGAIN) { + accountCreationDisabled = false; + Menu.a540fm(true); + } else if (var3 == Menu.DialogOption.MEMBERS) { + accountCreationDisabled = true; + a776qk(Menu.Id.MAIN); + } + this.b877(true); + } else { + this.b877(false); + } + } else if (f427kh()) { + final int var3 = this.tickCommonUI(true); + if (var3 == 2) { + if (fullScreenCanvas != null) { + removeFocusLossDetectingCanvas(); + } + JagexApplet.navigateToQuit(this); + } + this.b877(true); + } else if (Menu.isLobbyDialogOpen) { + if (_jbg == EnumJbg.C0) { + final int var3 = Menu.a137ch(); + if (var3 == 1) { + _nsob = true; + a776qk(Menu.Id.MAIN); + } + this.b877(true); + } else { + this.b877(false); + } + } else { + this.b877(false); + return false; + } + + return true; + } + + private static void l150spc() { + templateDictionary = new TemplateDictionary(); + templateDictionary.put("key", ""); + templateDictionary.put("highlight", ""); + templateDictionary.put("glossary", ""); + + for (int var2 = 0; var2 < 4; ++var2) { + templateDictionary.put("resource" + var2, Strings.format("><%1>", Integer.toString(GameView.RESOURCE_COLORS[var2], 16), StringConstants.RESOURCE_NAMES[var2].toLowerCase())); + templateDictionary.put("Resource" + var2, Strings.format("><%1>", Integer.toString(GameView.RESOURCE_COLORS[var2], 16), StringConstants.RESOURCE_NAMES[var2])); + } + + templateDictionary.put("territories", StringConstants.TAB_NAME_PRODUCTION); + templateDictionary.put("uioptions", StringConstants.TAB_NAME_UI_OPTIONS); + templateDictionary.put("fleetinfo", StringConstants.TAB_NAME_FLEET_INFO); + templateDictionary.put("projects", StringConstants.TAB_NAME_PROJECTS); + templateDictionary.put("diplomacy", StringConstants.TAB_NAME_DIPLOMACY); + templateDictionary.put("messages", StringConstants.TAB_NAME_MESSAGES); + templateDictionary.put("colmetal", Integer.toString(GameView.RESOURCE_COLORS[0], 16)); + templateDictionary.put("colbiomass", Integer.toString(GameView.RESOURCE_COLORS[1], 16)); + templateDictionary.put("colenergy", Integer.toString(GameView.RESOURCE_COLORS[2], 16)); + templateDictionary.put("colexotics", Integer.toString(GameView.RESOURCE_COLORS[3], 16)); + final String var3 = "><%1>"; + templateDictionary.put("project_metal", Strings.format(var3, Integer.toString(GameView.RESOURCE_COLORS[0], 16), StringConstants.PROJECT_NAMES[0].toLowerCase())); + templateDictionary.put("project_biomass", Strings.format(var3, Integer.toString(GameView.RESOURCE_COLORS[1], 16), StringConstants.PROJECT_NAMES[1].toLowerCase())); + templateDictionary.put("project_energy", Strings.format(var3, Integer.toString(GameView.RESOURCE_COLORS[2], 16), StringConstants.PROJECT_NAMES[2].toLowerCase())); + templateDictionary.put("Project_Metal", Strings.format(var3, Integer.toString(GameView.RESOURCE_COLORS[0], 16), StringConstants.PROJECT_NAMES[0])); + templateDictionary.put("Project_Biomass", Strings.format(var3, Integer.toString(GameView.RESOURCE_COLORS[1], 16), StringConstants.PROJECT_NAMES[1])); + templateDictionary.put("Project_Energy", Strings.format(var3, Integer.toString(GameView.RESOURCE_COLORS[2], 16), StringConstants.PROJECT_NAMES[2])); + templateDictionary.put("Project_Exotics", Strings.format(var3, Integer.toString(GameView.RESOURCE_COLORS[3], 16), StringConstants.PROJECT_NAMES[3])); + templateDictionary.put("PROJECT_METAL", Strings.format(var3, Integer.toString(GameView.RESOURCE_COLORS[0], 16), StringConstants.PROJECT_NAMES[0].toUpperCase())); + templateDictionary.put("PROJECT_BIOMASS", Strings.format(var3, Integer.toString(GameView.RESOURCE_COLORS[1], 16), StringConstants.PROJECT_NAMES[1].toUpperCase())); + templateDictionary.put("PROJECT_ENERGY", Strings.format(var3, Integer.toString(GameView.RESOURCE_COLORS[2], 16), StringConstants.PROJECT_NAMES[2].toUpperCase())); + templateDictionary.put("PROJECT_EXOTICS", Strings.format(var3, Integer.toString(GameView.RESOURCE_COLORS[3], 16), StringConstants.PROJECT_NAMES[3].toUpperCase())); + } + + private boolean loadNext() { + initializeUiStrings(); + if (ResourceLoader.SHATTERED_PLANS_SFX_1 != null) { + if (!ResourceLoader.COMMON_SPRITES.isIndexLoaded() || !ResourceLoader.COMMON_SPRITES.loadGroupData("basic")) { + CommonUI.setLoadProgress(10.0F, loadingMessage(ResourceLoader.COMMON_SPRITES, "basic", StringConstants.WAITING_FOR_GRAPHICS, StringConstants.LOADING_GRAPHICS)); + return false; + } else if (!ResourceLoader.COMMON_SPRITES.isIndexLoaded() || !ResourceLoader.COMMON_SPRITES.loadGroupData("lobby")) { + CommonUI.setLoadProgress(13.0F, loadingMessage(ResourceLoader.COMMON_SPRITES, "lobby", StringConstants.WAITING_FOR_GRAPHICS, StringConstants.LOADING_GRAPHICS)); + return false; + } else if (!ResourceLoader.COMMON_FONTS.isIndexLoaded() || !ResourceLoader.COMMON_FONTS.loadGroupData("lobby")) { + CommonUI.setLoadProgress(17.0F, loadingMessage(ResourceLoader.COMMON_FONTS, "lobby", StringConstants.WAITING_FOR_FONTS, StringConstants.LOADING_FONTS)); + return false; + } else if (!ResourceLoader.SHATTERED_PLANS_SFX_1.isIndexLoaded() || !ResourceLoader.SHATTERED_PLANS_SFX_1.loadAllGroups()) { + CommonUI.setLoadProgress(20.0F, loadingMessage(ResourceLoader.SHATTERED_PLANS_SFX_1, "", StringConstants.WAITING_FOR_SOUND_EFFECTS, StringConstants.LOADING_SOUND_EFFECTS)); + return false; + } else if (!ResourceLoader.SHATTERED_PLANS_SFX_2.isIndexLoaded() || !ResourceLoader.SHATTERED_PLANS_SFX_2.loadAllGroups()) { + CommonUI.setLoadProgress(40.0F, loadingMessage(ResourceLoader.SHATTERED_PLANS_SFX_2, "", StringConstants.WAITING_FOR_SOUND_EFFECTS, StringConstants.LOADING_SOUND_EFFECTS)); + return false; + } else if (!ResourceLoader.SHATTERED_PLANS_MUSIC_1.isIndexLoaded() || !ResourceLoader.SHATTERED_PLANS_MUSIC_1.loadAllGroups()) { + CommonUI.setLoadProgress(45.0F, loadingMessage0(ResourceLoader.SHATTERED_PLANS_MUSIC_1, StringConstants.WAITING_FOR_MUSIC, StringConstants.LOADING_MUSIC)); + return false; + } else if (!ResourceLoader.SHATTERED_PLANS_MUSIC_2.isIndexLoaded() || !ResourceLoader.SHATTERED_PLANS_MUSIC_2.loadAllGroups()) { + CommonUI.setLoadProgress(60.0F, loadingMessage(ResourceLoader.SHATTERED_PLANS_MUSIC_2, "", StringConstants.WAITING_FOR_MUSIC, StringConstants.LOADING_MUSIC)); + return false; + } else if (!ResourceLoader.SHATTERED_PLANS_SPRITES.isIndexLoaded() || !ResourceLoader.SHATTERED_PLANS_SPRITES.loadGroupData("")) { + CommonUI.setLoadProgress(75.0F, loadingMessage(ResourceLoader.SHATTERED_PLANS_SPRITES, "", StringConstants.WAITING_FOR_GRAPHICS, StringConstants.LOADING_GRAPHICS)); + return false; + } else if (!ResourceLoader.SHATTERED_PLANS_JPEGS.isIndexLoaded() || !ResourceLoader.SHATTERED_PLANS_JPEGS.loadAllGroups()) { + CommonUI.setLoadProgress(75.0F, loadingMessage(ResourceLoader.SHATTERED_PLANS_JPEGS, "", StringConstants.WAITING_FOR_GRAPHICS, StringConstants.LOADING_GRAPHICS)); + return false; + } else if (!ResourceLoader.SHATTERED_PLANS_FONTS.isIndexLoaded() || !ResourceLoader.SHATTERED_PLANS_FONTS.loadAllGroups()) { + CommonUI.setLoadProgress(75.0F, loadingMessage(ResourceLoader.SHATTERED_PLANS_FONTS, "", StringConstants.WAITING_FOR_GRAPHICS, StringConstants.LOADING_GRAPHICS)); + return false; + } else if (!ResourceLoader.SHATTERED_PLANS_STRINGS_2.isIndexLoaded() || !ResourceLoader.SHATTERED_PLANS_STRINGS_2.loadAllGroups()) { + CommonUI.setLoadProgress(75.0F, loadingMessage(ResourceLoader.SHATTERED_PLANS_STRINGS_2, "", StringConstants.WAITING_FOR_EXTRA_DATA, StringConstants.LOADING_EXTRA_DATA)); + return false; + } else if (!ResourceLoader.HUFFMAN_CODES.isIndexLoaded() || !ResourceLoader.HUFFMAN_CODES.loadAllGroups()) { + CommonUI.setLoadProgress(75.0F, loadingMessage(ResourceLoader.HUFFMAN_CODES, "", StringConstants.WAITING_FOR_EXTRA_DATA, StringConstants.LOADING_EXTRA_DATA)); + return false; + } else if (!ResourceLoader.QUICK_CHAT_DATA.isIndexLoaded() || !ResourceLoader.QUICK_CHAT_DATA.loadAllGroups()) { + CommonUI.setLoadProgress(75.0F, loadingMessage(ResourceLoader.QUICK_CHAT_DATA, StringConstants.WAITING_FOR_EXTRA_DATA, StringConstants.LOADING_EXTRA_DATA)); + return false; + } else { + CommonUI.switchToLoadingScreen(); + CommonUI.setLoadProgress(65.0F, StringConstants.UNPACKING_SOUND_EFFECTS); + this.render(); + Sounds.loadSoundEffects(ResourceLoader.SHATTERED_PLANS_SFX_1, ResourceLoader.SHATTERED_PLANS_SFX_2); + ResourceLoader.SHATTERED_PLANS_SFX_1 = null; + ResourceLoader.SHATTERED_PLANS_SFX_2 = null; + resetFrameClock(); + return false; + } + } else if (ResourceLoader.SHATTERED_PLANS_MUSIC_2 != null) { + CommonUI.setLoadProgress(75.0F, StringConstants.UNPACKING_MUSIC); + this.render(); + Sounds.loadMusic(ResourceLoader.SHATTERED_PLANS_MUSIC_2, ResourceLoader.SHATTERED_PLANS_MUSIC_1); + ResourceLoader.SHATTERED_PLANS_MUSIC_1 = null; + ResourceLoader.SHATTERED_PLANS_MUSIC_2 = null; + resetFrameClock(); + return false; + } else if (ResourceLoader.SHATTERED_PLANS_FONTS != null) { + CommonUI.setLoadProgress(90.0F, StringConstants.UNPACKING_GRAPHICS); + this.render(); + a780ck(ResourceLoader.COMMON_SPRITES, ResourceLoader.COMMON_FONTS, ResourceLoader.SHATTERED_PLANS_SPRITES, ResourceLoader.SHATTERED_PLANS_FONTS); + ResourceLoader.COMMON_FONTS = null; + ResourceLoader.SHATTERED_PLANS_FONTS = null; + ResourceLoader.QUICK_CHAT_DATA = null; + resetFrameClock(); + return false; + } else if (ResourceLoader.SHATTERED_PLANS_JPEGS != null) { + loadJpegImages(ResourceLoader.SHATTERED_PLANS_JPEGS); + ResourceLoader.SHATTERED_PLANS_JPEGS = null; + resetFrameClock(); + return false; + } else if (ResourceLoader.SHATTERED_PLANS_STRINGS_2 != null) { + TutorialMessages.load(ResourceLoader.SHATTERED_PLANS_STRINGS_2); + StarSystem.loadNames(ResourceLoader.SHATTERED_PLANS_STRINGS_2); + ResourceLoader.SHATTERED_PLANS_STRINGS_2 = null; + resetFrameClock(); + return false; + } else if (ResourceLoader.HUFFMAN_CODES == null) { + l150spc(); + a487er(); + IntroAnimation.reset(); + + for (int group = 0; group < Menu.NUM_GROUPS; ++group) { + if (group == 11) continue; + //noinspection MagicConstant + Menu.menus[group] = new Menu(group); + } + + Menu.nextMenu = Menu.Id.MAIN; + debugModeEnabled = adminLevel >= 2; + GameUI.lastSavedSettings = -1; + Menu.currentMenu = Menu.Id.MAIN; + GameUI.currentSettings = -1; + resetFrameClock(); + a827jo(currentTrack, 0x100000, true); + return true; + } else { + HuffmanCoder.initialize(ResourceLoader.HUFFMAN_CODES); + ResourceLoader.HUFFMAN_CODES = null; + resetFrameClock(); + return false; + } + } + + private void b877(final boolean var2) { + if (_jbg == EnumJbg.C0) { + boolean var3 = false; + boolean var4 = false; + if (!var2) { + if (Menu.currentMenu == Menu.nextMenu) { + if (Menu.currentMenu == Menu.Id.GAME) { + if (inLobbyBrowser) { + var3 = true; + var4 = true; + } else { + ClientGameSession.playSession.tick(true); + + while (nextTypedKey()) { + ClientGameSession.playSession.handleKeyTyped(); + } + } + } else if (Menu.currentMenu == Menu.Id.LOBBY) { + var3 = true; + } else if (Menu.currentMenu == Menu.Id.INTRODUCTION) { + IntroAnimation.tick(); + } else if (Menu.currentMenu >= 0) { + Menu.menus[Menu.currentMenu].i150(); + } + } else { + if (Menu._ehQ != 0 || !(Menu.currentMenu >= 0) || Menu.menus[Menu.currentMenu].a427()) { + ++Menu._ehQ; + } + + if (Menu._ehQ == 32) { + switchMenus(); + } + } + } + + if (inLobbyBrowser && !_mdQ && !_isa) { + if (playingGame && isChatboxSelected) { + var3 = false; + } + + a430cf(var3); + if (spectatingGame) { + ClientGameSession.spectateSession.tick(var4); + } + if (playingGame) { + a778cf(var4); + ClientGameSession.playSession.tick(var4); + } + + label172: + while (true) { + do { + if (!nextTypedKey()) { + break label172; + } + + if (!playingGame) { + a111qf(); + break; + } + } while (processChatKeyInput()); + if (spectatingGame) { + ClientGameSession.spectateSession.handleKeyTyped(); + } + if (playingGame) { + ClientGameSession.playSession.handleKeyTyped(); + } + } + } + + if (!inLobbyBrowser) { + b150af(); + } + + if (GameUI._gen) { + if (_flh < 20) { + ++_flh; + } + } else if (_flh > 0) { + --_flh; + } + + final int var5 = 400; + final int var6 = -(_flh * _flh) + var5; + final int var7 = 120 * var6 / var5 + 360; + a366fa(var7); + if (IntroAnimation._ucv > 0) { + --IntroAnimation._ucv; + } + + if (!this.achievementNotifications.isEmpty() && ++this.achievementNotificationTimer == 335) { + this.achievementNotificationTimer = 0; + this.achievementNotifications.remove(); + } + } else if (_jbg == EnumJbg.C1) { + ++_naF; + if (_naF == 16) { + a487oq(!accountCreationDisabled); + _jbg = EnumJbg.C2; + } + } else if (_jbg == EnumJbg.C2) { + if (!isAnonymous) { + debugModeEnabled = adminLevel >= 2; + Menu.nextMenu = initialMenu; + a714jc(SpriteResource.loadSprite(ResourceLoader.COMMON_SPRITES, "basic", "unachieved")); + Menu.closeLobbyDialog(); + if (accountCreationDisabled) { + accountCreationDisabled = false; + Menu.a540fm(false); + } + + if (_nsob) { + Menu.switchTo(Menu.Id.LOADING_LOBBY, Menu.nextMenu, false); + } + + if (Menu.nextMenu >= 0) { + switchMenus(); + } + + Menu.updateAvailableMenuItems(); + } + + _nsob = false; + accountCreationDisabled = false; + _jbg = EnumJbg.C3; + } else { + --_naF; + if (_naF == 0) { + _jbg = EnumJbg.C0; + } + } + + if (Menu.nextMenu == Menu.Id.SKIRMISH) { + final String[] playerNames = new String[]{StringConstants.EMPIRE_NAMES[0], StringConstants.EMPIRE_NAMES[1], StringConstants.EMPIRE_NAMES[2], StringConstants.EMPIRE_NAMES[3]}; + ClientGameSession.playSession = new ClientGameSession(false, false, 4, Menu.gameOptions, Menu.skirmishGameType, playerNames, 0, false, null); + Menu.switchTo(Menu.Id.GAME, 0, false); + _tli = true; + } + + if (Menu.nextMenu == Menu.Id.TUTORIAL) { + final String[] playerNames = new String[]{StringConstants.EMPIRE_NAMES[0]}; + ClientGameSession.playSession = new ClientGameSession(false, true, 0, GameOptions.STREAMLINED_GAME_OPTIONS, GameState.GameType.CONQUEST, playerNames, 0, false, null); + Menu.switchTo(Menu.Id.GAME, 0, false); + _tli = true; + } + + if (Menu.nextMenu == Menu.Id.LEAVE_GAME_TO_LOBBY) { + C2SPacket.requestToLeaveRoom(unratedLobbyRoom.roomId); + Menu.nextMenu = Menu.currentMenu; + _isa = true; + } + } + + @Override + protected void render() { + final Canvas canvas = fullScreenCanvas == null ? JagexBaseApplet.canvas : fullScreenCanvas; + if (!isConnectedAndLoaded()) { + a985no(canvas); + } else if (!isFullyLoaded) { + CommonUI.drawLoading(); + JagexBaseApplet.paint(canvas); + } else if (isProfileInitialized()) { + if (Menu.nextMenu == Menu.currentMenu) { + if (Menu.currentMenu == Menu.Id.LOBBY) { + Drawing.clear(); + } else { + a877u(Menu.currentMenu == Menu.Id.GAME); + if (Menu.currentMenu != Menu.nextMenu || Menu.currentMenu != Menu.Id.LOBBY) { + n423(); + } + + if (Menu.currentMenu >= 0) { + Menu.menus[Menu.currentMenu].g150(); + } + } + } else { + a877u(Menu.currentMenu == Menu.Id.GAME); + if (Menu.currentMenu != Menu.nextMenu || Menu.currentMenu != Menu.Id.LOBBY) { + n423(); + } + + if (Menu.currentMenu >= 0 && !(Menu.nextMenu >= 0)) { + Menu.menus[Menu.currentMenu].b093(128 * Menu._ehQ / 32); + } else if (!(Menu.currentMenu >= 0) && Menu.nextMenu >= 0) { + Menu.menus[Menu.nextMenu].b093(-(Menu._ehQ * 128 / 32) + 128); + } else if (Menu.currentMenu >= 0) { + Menu.menus[Menu.currentMenu].c326(Menu.nextMenu, 128 * Menu._ehQ / 32); + } + } + + if (Menu.nextMenu != Menu.currentMenu) { + if (Menu.nextMenu == Menu.Id.LOBBY) { + Drawing.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 256 * Menu._ehQ / 32); + } else if (Menu.currentMenu == Menu.Id.LOBBY) { + Drawing.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, -(256 * Menu._ehQ / 32) + 256); + } + } + + if (!_cjx || !_tli) { + a813qr(a154vc()); + } + + if (_ebb > 0) { + Drawing.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, _ebb); + } + + if (Menu.isFullscreenDialogOpen) { + a326ts(a137sa(), Menu._dmra); + a423kd(); + } else if (f427kh()) { + a630gr(true); + } else if (Menu.isLobbyDialogOpen) { + + a326ts(Menu._ahR - Menu._ldj, Menu._rnb); + Menu.a150rg(); + } else { + Optional.ofNullable(this.achievementNotifications.poll()).ifPresent(var3 -> { + final String name = StringConstants.ACHIEVEMENT_NAMES[var3.achievementIndex]; + final int maxWidth = Menu.FONT.measureLineWidth(name) + 50; + + final int t; + if (this.achievementNotificationTimer > 303) { + t = 335 - this.achievementNotificationTimer; + } else { + t = Math.min(this.achievementNotificationTimer, 32); + } + final int width = MathUtil.ease(t, 32, 0, maxWidth); + final int height = 36; + final int x = 10 + (maxWidth - width >> 1); + final int y = 10; + Menu.drawShine(x, y, width, height); + Drawing.withBounds(x, y, x + width, y + height, () -> { + final int var7 = 10 + (maxWidth / 2); + Menu.achievementIcon(var3.achievementIndex).draw(var7 + maxWidth / 2 - 36, 14); + Menu.FONT.draw(name, var7 - (maxWidth / 2) + 10, (Menu.FONT.ascent + height >> 1) - 2 + y, 0x2ad0d6); + }); + }); + } + + if (_jbg != EnumJbg.C0) { + final int var14 = _naF * 256 / 16; + if (var14 > 0) { + Drawing.fillRect(0, 0, Drawing.width, Drawing.height, 0, var14); + } + } + + if (drawDebugStats && debugModeEnabled) { + Menu.FONT.draw(Integer.toString(JagexBaseApplet.lastFrameScore), 4, 4 + Menu.FONT.ascent, Drawing.WHITE); + final long var15 = Runtime.getRuntime().totalMemory(); + final long var16 = Runtime.getRuntime().freeMemory(); + final long var17 = var15 - var16; + Menu.FONT.draw((int) (var17 >> 10) + "kb", 4, 2 * Menu.FONT.ascent + 8, Drawing.WHITE); + } + + JagexBaseApplet.paint(canvas); + } else { + CommonUI.setLoadProgress(100.0F, StringConstants.LOADING_EXTRA_DATA); + CommonUI.drawLoading(); + JagexBaseApplet.paint(canvas); + } + } + + private enum EnumJbg { + C0, C1, C2, C3 + } +} diff --git a/src/main/java/funorb/shatteredplans/client/Sounds.java b/src/main/java/funorb/shatteredplans/client/Sounds.java new file mode 100644 index 0000000..eec8e72 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/Sounds.java @@ -0,0 +1,99 @@ +package funorb.shatteredplans.client; + +import funorb.audio.MusicTrack; +import funorb.audio.PlayingSound; +import funorb.audio.SampledAudioChannel; +import funorb.audio.SoundEffect; +import funorb.audio.SoundLoader; +import funorb.audio.al_; +import funorb.audio.h_; +import funorb.audio.kk_; +import funorb.audio.vk_; +import funorb.cache.ResourceLoader; + +import java.util.ArrayList; +import java.util.List; + +public final class Sounds { + public static final int MAX_VOLUME = 256; + + public static SoundEffect SFX_FACTORY_NOISE; + public static SoundEffect SFX_SHIP_SELECTION; + public static SoundEffect SFX_SHIP_MOVE_ORDER; + public static SoundEffect SFX_SHIP_ATTACK_ORDER; + public static SoundEffect SFX_EXPLOSION; + public static SoundEffect SFX_NEXT_OPEN; + public static SoundEffect SFX_NEXT_CLOSE; + public static MusicTrack MUSIC_INTRO; + public static MusicTrack MUSIC_IN_GAME_2; + public static MusicTrack MUSIC_IN_GAME_1; + public static MusicTrack MUSIC_WIN; + public static MusicTrack MUSIC_LOSE; + + public static int soundVolume = 256; + public static int musicVolume = 256; + + public static final List playingSounds = new ArrayList<>(); + public static vk_ soundsTn; + public static h_ musicTn; + static SampledAudioChannel soundsChannel; + static SampledAudioChannel musicChannel; + + public static void loadSoundEffects(final ResourceLoader loader1, final ResourceLoader loader2) { + SoundLoader.globalLoader = new SoundLoader(loader1, loader2); + + SFX_SHIP_SELECTION = SoundEffect.load1("shatteredplans_ship_selection", 256); + SFX_SHIP_MOVE_ORDER = SoundEffect.load1("shatteredplans_ship_move_order", 256); + SFX_SHIP_ATTACK_ORDER = SoundEffect.load1("shatteredplans_ship_attack_order", 256); + SFX_FACTORY_NOISE = SoundEffect.load1("shatteredplans_factory_noise", 256); + SFX_EXPLOSION = SoundEffect.load2("shatteredplans_explosion", 120); + SFX_NEXT_OPEN = SoundEffect.load1("shatteredplans_next_open", 256); + SFX_NEXT_CLOSE = SoundEffect.load1("shatteredplans_next_close", 256); + } + + public static void loadMusic(final ResourceLoader loader1, final ResourceLoader loader2) { + MUSIC_INTRO = MusicTrack.load(loader1, "shattered_plans_intro"); + MUSIC_IN_GAME_1 = MusicTrack.load(loader1, "shattered_plans_ingame"); + MUSIC_IN_GAME_2 = MusicTrack.load(loader1, "shattered_plans_ingame_two"); + MUSIC_WIN = MusicTrack.load(loader1, "shattered_plans_win"); + MUSIC_LOSE = MusicTrack.load(loader1, "shattered_plans_lose"); + + ShatteredPlansClient.currentTrack = MUSIC_IN_GAME_2; + musicTn._u.a350(SoundLoader.globalLoader, loader2, MUSIC_INTRO); + musicTn._u.a350(SoundLoader.globalLoader, loader2, MUSIC_IN_GAME_1); + musicTn._u.a350(SoundLoader.globalLoader, loader2, MUSIC_IN_GAME_2); + musicTn._u.f150(); + + SoundLoader.globalLoader = null; + } + + public static void play(final SoundEffect effect) { + play(effect._f, effect.volume); + } + + public static PlayingSound play(final SoundEffect effect, final int volume) { + return play(effect._f, effect.volume * volume / 96); + } + + private static PlayingSound play(final kk_ var1, final int volume) { + final al_ var01 = al_.a638(var1, volume); + assert var01 != null; + final PlayingSound sound = new PlayingSound(var01); + playingSounds.add(sound); + soundsTn.addFirst(var01); + return sound; + } + + static void setSoundVolume(final int volume) { + soundVolume = volume; + playingSounds.removeIf(sound -> !sound._p.isLinked()); + playingSounds.forEach(sound -> sound._p.setVolume(sound.volume * soundVolume + 128 >> 8)); + } + + public static void setMusicVolume(final int volume) { + musicVolume = volume; + if (musicTn != null) { + musicTn.setVolume(volume); + } + } +} diff --git a/src/main/java/funorb/shatteredplans/client/TutorialMessage.java b/src/main/java/funorb/shatteredplans/client/TutorialMessage.java new file mode 100644 index 0000000..85aa044 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/TutorialMessage.java @@ -0,0 +1,69 @@ +package funorb.shatteredplans.client; + +import funorb.shatteredplans.client.game.TutorialObjective; +import org.intellij.lang.annotations.MagicConstant; + +public final class TutorialMessage { + public String body = ""; + public int _q; + public int _j; + String nextId; + public String[] _m; + public TutorialMessage next; + @MagicConstant(valuesFromClass = Anchor.class) + public + int anchor; + public int _t; + public TutorialObjective[] objectives; + public boolean clearStack; + boolean endThread; + public int _b; + public boolean noStack; + String tag = null; + private String[] _e; + + void a984(final String var2) { + if (this._m == null) { + this._m = new String[]{var2}; + } else { + final int var3 = this._m.length; + final String[] var4 = new String[var3 + 1]; + System.arraycopy(this._m, 0, var4, 0, var3); + this._m = var4; + this._m[var3] = var2; + } + } + + public void a627(final String var1) { + if (this._e == null) { + this._e = new String[]{var1}; + } else { + final int var3 = this._e.length; + final String[] var4 = new String[1 + var3]; + + System.arraycopy(this._e, 0, var4, 0, var3); + + this._e = var4; + this._e[var3] = var1; + } + } + + public void addObjective(final TutorialObjective objective) { + if (this.objectives == null) { + this.objectives = new TutorialObjective[]{objective}; + } else { + final int prevLen = this.objectives.length; + final TutorialObjective[] objectives = new TutorialObjective[prevLen + 1]; + System.arraycopy(this.objectives, 0, objectives, 0, prevLen); + this.objectives = objectives; + this.objectives[prevLen] = objective; + } + } + + public static final class Anchor { + public static final int TOP_LEFT = 0; + public static final int TOP_RIGHT = 1; + public static final int BOTTOM_LEFT = 2; + public static final int BOTTOM_RIGHT = 3; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/TutorialMessageId.java b/src/main/java/funorb/shatteredplans/client/TutorialMessageId.java new file mode 100644 index 0000000..680419f --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/TutorialMessageId.java @@ -0,0 +1,9 @@ +package funorb.shatteredplans.client; + +public final class TutorialMessageId { + public final String key; + + public TutorialMessageId(final String key) { + this.key = key; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/TutorialMessages.java b/src/main/java/funorb/shatteredplans/client/TutorialMessages.java new file mode 100644 index 0000000..6a779f9 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/TutorialMessages.java @@ -0,0 +1,183 @@ +package funorb.shatteredplans.client; + +import funorb.Strings; +import funorb.cache.ResourceLoader; +import funorb.shatteredplans.client.game.TutorialObjective; +import org.intellij.lang.annotations.MagicConstant; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public final class TutorialMessages { + private static TutorialMessage[] tutorialMessages; + + private static String[] lines; + private static int nextLineIndex; + private static String currentLine; + + public static void load(final ResourceLoader var0) { + lines = readLines(Objects.requireNonNull(var0.getResource("", "tutorial.txt"))); + if (lines.length == 0) { + tutorialMessages = null; + } else { + nextLineIndex = 0; + advanceLine(); + final List messages = Stream.iterate(parseMessage(), Objects::nonNull, var2 -> parseMessage()).toList(); + + tutorialMessages = messages.toArray(new TutorialMessage[0]); + + for (int i = 0; i < messages.size() - 1; ++i) { + final String nextId = tutorialMessages[i].nextId; + TutorialMessage next = nextId == null ? null : get(nextId); + if (next == null && !tutorialMessages[i].endThread) { + next = tutorialMessages[i + 1]; + } + + tutorialMessages[i].next = next; + } + } + } + + public static TutorialMessage get(final String var0) { + return Arrays.stream(tutorialMessages) + .filter(var3 -> var0.equalsIgnoreCase(var3.tag)) + .findFirst().orElse(null); + } + + private static void advanceLine() { + if (nextLineIndex < lines.length) { + currentLine = lines[nextLineIndex++]; + } else { + currentLine = null; + } + } + + private static TutorialMessage parseMessage() { + for (; currentLine != null; advanceLine()) { + if (currentLine.charAt(0) == '[') { + final TutorialMessage message = new TutorialMessage(); + final StringBuilder sb = new StringBuilder(); + advanceLine(); + + for (; currentLine != null && currentLine.charAt(0) != '['; advanceLine()) { + if (currentLine.charAt(0) == '@') { + final int var3 = currentLine.indexOf(' '); + final String var4; + final String[] args; + if (var3 == -1) { + var4 = currentLine.substring(1); + args = null; + } else { + var4 = currentLine.substring(1, var3); + args = parseArguments(currentLine.substring(var3)); + } + + if (var4.equalsIgnoreCase("topleft")) { + setMessagePosition(message, TutorialMessage.Anchor.TOP_LEFT, Objects.requireNonNull(args)); + } else if (var4.equalsIgnoreCase("topright")) { + setMessagePosition(message, TutorialMessage.Anchor.TOP_RIGHT, Objects.requireNonNull(args)); + } else if (var4.equalsIgnoreCase("bottomleft")) { + setMessagePosition(message, TutorialMessage.Anchor.BOTTOM_LEFT, Objects.requireNonNull(args)); + } else if (var4.equalsIgnoreCase("bottomright")) { + setMessagePosition(message, TutorialMessage.Anchor.BOTTOM_RIGHT, Objects.requireNonNull(args)); + } else if (var4.equalsIgnoreCase("tag")) { + message.tag = Objects.requireNonNull(args)[0]; + } else if (var4.equalsIgnoreCase("next")) { + message.nextId = Objects.requireNonNull(args)[0]; + } else if (var4.equalsIgnoreCase("objective")) { + addMessageObjective(message, Objects.requireNonNull(args)); + } else if (var4.equalsIgnoreCase("action")) { + setMessageAction(message, Objects.requireNonNull(args)); + } else if (var4.equalsIgnoreCase("flag")) { + setMessageFlag(message, Objects.requireNonNull(args)); + } else if (var4.equalsIgnoreCase("endthread")) { + message.endThread = true; + } else if (var4.equalsIgnoreCase("nostack")) { + message.noStack = true; + } else if (var4.equalsIgnoreCase("clearstack")) { + message.clearStack = true; + } + } else { + sb.append(currentLine); + sb.append(' '); + } + } + + message.body = sb.toString(); + return message; + } + } + + return null; + } + + private static String[] readLines(final byte[] data) { + final List lines = new ArrayList<>(); + int pos = 0; + int lineStart = 0; + while (pos < data.length) { + while (pos < data.length && (data[pos] != '\n' && data[pos] != '\r')) { + ++pos; // advance until next newline character + } + + lines.add(Strings.decode1252String(data, lineStart, pos - lineStart)); + + while (pos < data.length && (data[pos] == '\n' || data[pos] == '\r')) { + ++pos; // advance past newline characters + } + lineStart = pos; + } + + return lines.toArray(new String[0]); + } + + private static String[] parseArguments(final String var0) { + return Arrays.stream(var0.split(",")) + .map(String::trim) + .filter(Predicate.not(String::isEmpty)) + .toArray(String[]::new); + } + + private static void setMessagePosition(final TutorialMessage var2, + @MagicConstant(valuesFromClass = TutorialMessage.Anchor.class) final int anchor, + final String[] args) { + var2.anchor = anchor; + var2._t = autoOrInteger(args[0]); + var2._b = autoOrInteger(args[1]); + var2._j = autoOrInteger(args[2]); + var2._q = autoOrInteger(args[3]); + } + + private static int autoOrInteger(final String str) { + return str.equalsIgnoreCase("auto") ? -1 : Strings.parseDecimalInteger(str); + } + + private static void setMessageAction(final TutorialMessage message, final String[] args) { + for (final String var5 : args) { + message.a984(var5); + } + } + + private static void setMessageFlag(final TutorialMessage message, final String[] args) { + for (final String var4 : args) { + message.a627(var4); + } + } + + private static void addMessageObjective(final TutorialMessage message, final String[] args) { + final TutorialObjective var3 = new TutorialObjective(); + var3.key = args[0]; + if (args.length > 2) { + var3.description = Arrays.stream(args, 2, args.length) + .collect(Collectors.joining(", ", args[1], "")); + } else { + var3.description = args[1]; + } + message.addObjective(var3); + } +} diff --git a/src/main/java/funorb/shatteredplans/client/game/AbstractGameView.java b/src/main/java/funorb/shatteredplans/client/game/AbstractGameView.java new file mode 100644 index 0000000..12c2db7 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/AbstractGameView.java @@ -0,0 +1,604 @@ +package funorb.shatteredplans.client.game; + +import funorb.graphics.Point; +import funorb.graphics.Rect; +import funorb.graphics.Sprite; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.CombatEngagementAnimationState; +import funorb.shatteredplans.client.GameUI; +import funorb.shatteredplans.client.JagexApplet; +import funorb.shatteredplans.client.ShatteredPlansClient; +import funorb.shatteredplans.game.ContiguousForce; +import funorb.shatteredplans.game.GameState; +import funorb.shatteredplans.game.MoveFleetsOrder; +import funorb.shatteredplans.game.Player; +import funorb.shatteredplans.game.ProjectOrder; +import funorb.shatteredplans.map.Map; +import funorb.shatteredplans.map.StarSystem; +import funorb.shatteredplans.map.TannhauserLink; +import funorb.util.IsaacRandom; +import org.intellij.lang.annotations.MagicConstant; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Random; + +public abstract class AbstractGameView { + public static final float TWO_HUNDRED_F = 200.0F; + protected final int[][] projectHighlightColors; + public int lastTickMouseX; + protected Player[] _ib; + protected Map map; + protected GameUI gameUI; + protected int[][] _cb; + public float mapScrollPosnY; + protected float targetZoomFactor; + public float mapScrollPosnX; + public float unitScalingFactor; + public float maxUnitScalingFactor; + protected final Player localPlayer; + protected float targetScrollPosnY; + public ContiguousForce _fb; + public int lastTickMouseY; + protected float targetScrollPosnX; + public boolean isAnimatingViewport; + public StarSystem targetedSystem; + public MoveFleetsOrder selectedFleetOrder; + protected int[] possibleSystemCollapseStages; + protected Random random; + protected int animationTick; + public SystemHighlight[] highlightedSystems; + protected int[] systemDrawX; + protected List combatEngagements; + protected int[] clonedRemainingGarrisons; + protected boolean[] willOwnSystem; + protected int _n; + protected int[] systemCollapseStages; + private int largestFleetMovement; + protected int largestFleetBuildQuantity; + protected List fleetMovements; + protected List collapseRetreats; + protected Rect[] systemBounds; + protected List combatExplosions; + protected int[][] systemHexes; + protected List buildEvents; + protected Player[] clonedSystemOwners; + protected Collection projectOrders; + protected List combatRetreats; + protected boolean[] canOwnSystem; + protected int[] systemDrawY; + protected Player[] systemOwners; + @MagicConstant(valuesFromClass = GameView.AnimationPhase.class) + public int animationPhase; + protected int buildPhases; + public int turnSeed; + protected boolean[] retreatTargets; + protected Collection tannhauserLinks; + private Player[] sessionSystemOwners; + private ContiguousForce[] systemForces; + private int[] remainingGarrisons; + private int[] systemGarrisons; + + protected AbstractGameView(final Player localPlayer) { + this.localPlayer = localPlayer; + this.projectHighlightColors = new int[4][]; + } + + private static boolean hitTest(final int[] points, final int x, final int y) { + int x1 = points[points.length - 2]; + int y1 = points[points.length - 1]; + int var6 = 0; + + for (int i = 0; i < points.length; i += 2) { + final int x2 = points[i]; + final int y2 = points[i + 1]; + if (hitTestHelper(x1, y1, x2, y2, x, y)) { + ++var6; + } + + x1 = x2; + y1 = y2; + } + + return (var6 & 1) == 1; + } + + private static boolean hitTestHelper(int x1, int y1, int x2, int y2, final int px, final int py) { + if (y1 == y2) { + return false; + } else { + if (y1 > y2) { + final int tmp1 = y1; + y1 = y2; + y2 = tmp1; + final int tmp2 = x1; + x1 = x2; + x2 = tmp2; + } + + if (y1 < py && py <= y2) { + return (py - y1) * (x2 - x1) > (px - x1) * (y2 - y1); + } else { + return false; + } + } + } + + private void addBuildProjectEvent(final StarSystem system, + final Player player, + @MagicConstant(valuesFromClass = GameState.ResourceType.class) final int type) { + final int phase = this.nextBuildPhase(system); + this.buildEvents.add(new BuildEvent(system, player, type, phase)); + if (phase >= this.buildPhases) { + this.buildPhases = phase + 1; + } + } + + private int nextBuildPhase(final StarSystem system) { + int phase = 0; + while (this.haveBuildEvent(system, phase)) { + ++phase; + } + return phase; + } + + public final void resetSystemState() { + final int systemCount = this.map.systems.length; + + if (this.systemOwners == null || this.systemOwners.length < this.map.systems.length) { + this.systemGarrisons = new int[systemCount]; + this.systemOwners = new Player[systemCount]; + this.retreatTargets = new boolean[systemCount]; + } + + for (int i = 0; i < systemCount; ++i) { + final StarSystem system = this.map.systems[i]; + this.systemOwners[i] = system.owner; + this.systemGarrisons[i] = system.garrison; + this.retreatTargets[i] = false; + } + } + + public final void setMap(final Map map) { + this.map = map; + this.maxUnitScalingFactor = (float) (this.map.drawingWidth * 300 / 450); + final SystemHighlight[] var3 = new SystemHighlight[this.map.systems.length]; + final boolean[] var4 = new boolean[this.map.systems.length]; + + for (int i = 0; i < this.highlightedSystems.length; ++i) { + var3[i] = this.highlightedSystems[i]; + var4[i] = this.retreatTargets[i]; + } + + this.highlightedSystems = var3; + this.retreatTargets = var4; + this.a487(); + } + + private void clearTurnEvents() { + this.fleetMovements.clear(); + this.combatEngagements.clear(); + this.buildEvents.clear(); + this.combatRetreats.clear(); + this.collapseRetreats.clear(); + this.largestFleetMovement = 0; + this.largestFleetBuildQuantity = 0; + this.buildPhases = 0; + } + + public final void setGameUI(final GameUI var1) { + this.gameUI = var1; + } + + public final void a968(final ContiguousForce var1) { + if (!var1.isEmpty()) { + int var5; + if (this._fb != var1) { + final int var3 = this.gameUI.getHeight(); + final short var4 = 320; + var5 = var3 / 2; + + for (final StarSystem var6 : var1) { + final int var7 = (int) ((-this.mapScrollPosnX + (float) var6.posnX) * (300.0F / (this.unitScalingFactor + (float) var6._z))) + var4; + final int var8 = var5 + (int) ((-this.mapScrollPosnY + (float) var6.posnY) * (300.0F / ((float) var6._z + this.unitScalingFactor))); + if (var7 >= 0 && var8 >= 0 && var7 < ShatteredPlansClient.SCREEN_WIDTH && var3 > var8) { + this._fb = var1; + return; + } + } + } + + final Rect var9 = this.a677(var1); + final Rect var10 = this.gameUI.b520(); + var5 = -var10.x1 + var10.x2; + final int var11 = var10.y2 - var10.y1; + float var12 = (float) ((var9.x2 - var9.x1) / var5); + if ((float) ((-var9.y1 + var9.y2) / var11) > var12) { + var12 = (float) ((var9.y2 - var9.y1) / var11); + } + + var12 = (float) ((double) var12 + 0.2D); + if (var12 < (float) 1) { + var12 = 1.0F; + } + + float var13 = (float) (var10.x1 + var10.x2 - ShatteredPlansClient.SCREEN_WIDTH >> 1); + var13 *= var12; + this.targetScrollPosnX = -var13 + (float) (var9.x2 + var9.x1 >> 1); + float v = (float) (var10.y1 + var10.y2 - this.gameUI.getHeight() >> 1); + v *= var12; + this.isAnimatingViewport = true; + this._fb = var1; + this.targetScrollPosnY = (float) (var9.y2 + var9.y1 >> 1) - v; + this.targetZoomFactor = var12 * 300.0F; + } + } + + private void addBuildFleetsEvent(final StarSystem system, final Player player, final int quantity) { + final int phase = this.nextBuildPhase(system); + this.buildEvents.add(new BuildEvent(system, player, -1, quantity, phase)); + if (phase >= this.buildPhases) { + this.buildPhases = phase + 1; + } + } + + public final void setTacticalOverlay(final boolean[] canOwnSystem, + final boolean[] willOwnSystem, + final int[] collapseStages, + final int[] possibleCollapseStages) { + this.possibleSystemCollapseStages = possibleCollapseStages; + this.systemCollapseStages = collapseStages; + this.canOwnSystem = canOwnSystem; + this.willOwnSystem = willOwnSystem; + } + + private void addBuildTannhauserEvent(final Player player, final StarSystem source, final StarSystem target) { + final int phase = this.nextTannhauserPhase(source, target); + this.buildEvents.add(new BuildEvent(target, player, GameState.ResourceType.EXOTICS, phase)); + this.buildEvents.add(new BuildEvent(source, player, GameState.ResourceType.EXOTICS, phase)); + if (phase >= this.buildPhases) { + this.buildPhases = phase + 1; + } + } + + private int nextTannhauserPhase(final StarSystem source, final StarSystem target) { + int phase = 0; + while (this.haveTannhauserEvent(phase) || this.haveBuildEvent(target, phase) || this.haveBuildEvent(source, phase)) { + ++phase; + } + return phase; + } + + private Rect a677(final ContiguousForce var2) { + final Rect var4 = new Rect(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); + + for (final StarSystem var3 : var2) { + for (final Point var7 : var3.hexPoints) { + if (var4.y1 > var7.y) { + var4.y1 = var7.y; + } + + if (var4.x1 > var7.x) { + var4.x1 = var7.x; + } + + if (var7.y > var4.y2) { + var4.y2 = var7.y; + } + + if (var4.x2 < var7.x) { + var4.x2 = var7.x; + } + } + } + + return var4; + } + + final void drawSystemIcon(final StarSystem system) { + final Sprite sprite = system.getSprite(); + sprite.b115( + this.systemDrawX[system.index] - 1 - (int) (TWO_HUNDRED_F * (float) sprite.width / (this.unitScalingFactor * 2.0F)), + this.systemDrawY[system.index] - 1 - (int) ((float) sprite.width * TWO_HUNDRED_F / (this.unitScalingFactor * 2.0F)), + (int) (TWO_HUNDRED_F * (float) sprite.width / this.unitScalingFactor), + (int) (TWO_HUNDRED_F * (float) sprite.width / this.unitScalingFactor)); + } + + public final void a815(final StarSystem var1) { + final Rect var3 = this.gameUI.b520(); + float var4 = 24000.0F / (float) (var3.x2 - var3.x1) - 3.0F * (float) var1._z; + if (var4 < TWO_HUNDRED_F) { + var4 = TWO_HUNDRED_F; + } + + this.a021(78, var1, var4); + } + + public final void stopCombatAnimations() { + this.animationPhase = AnimationPhase.NOT_PLAYING; + this.animationTick = 0; + this.gameUI.animationPlayingButton.deactivate(); + this.gameUI.animationPlayingButton.tooltip = StringConstants.TOOLTIP_ANIM_CLICK_TO_PLAY; + } + + private boolean haveBuildEvent(final StarSystem system, final int phase) { + return this.buildEvents.stream().anyMatch(event -> event.system == system && event.phase == phase); + } + + final StarSystem systemHexAtPoint(final int x, final int y) { + if (x >= 0 && y >= 0) { + return Arrays.stream(this.map.systems) + .filter(system -> this.systemBounds[system.index].contains(x, y) + && hitTest(this.systemHexes[system.index], x, y)) + .findFirst().orElse(null); + } + return null; + } + + public final void a021(final int var1, final StarSystem var2, final float var3) { + final Rect var4 = this.gameUI.b520(); + float var5 = (float) (var4.x2 - ShatteredPlansClient.SCREEN_WIDTH + var4.x1 >> 1); + var5 *= ((float) var2._z + var3) / 300.0F; + this.targetScrollPosnX = -var5 + (float) var2.posnX; + if (this.targetScrollPosnX < 0.0F) { + this.targetScrollPosnX = 0.0F; + } + + float v = (float) (var4.y2 + (var4.y1 - this.gameUI.getHeight()) >> 1); + v *= (var3 + (float) var2._z) / 300.0F; + this.targetScrollPosnY = (float) var2.posnY - v; + this.targetZoomFactor = var3; + if (var1 >= 7) { + this.isAnimatingViewport = true; + this._fb = null; + if (this.targetScrollPosnY < 0.0F) { + this.targetScrollPosnY = 0.0F; + } + + } + } + + final void drawBackground() { + final int var2 = ShatteredPlansClient.STAR_FIELD.width - ShatteredPlansClient.SCREEN_WIDTH; + final int var3 = ShatteredPlansClient.STAR_FIELD.height - ShatteredPlansClient.SCREEN_HEIGHT; + final int var4 = -(((int) this.mapScrollPosnX) * (var2 << 4)) / (this.map.drawingWidth); + final int var6 = -(((int) this.mapScrollPosnY) * (var3 << 4)) / (this.map.drawingHeight); + ShatteredPlansClient.STAR_FIELD.draw(var4 >> 4, var6 >> 4); + } + + public final void c487() { + this._fb = null; + this.isAnimatingViewport = true; + this.targetScrollPosnY = (float) (this.map.drawingHeight / 2); + this.targetZoomFactor = this.maxUnitScalingFactor; + this.targetScrollPosnX = (float) (this.map.drawingWidth / 2); + } + + public final void assignSystemState(final int[] remainingGarrisons, final ContiguousForce[] systemForces, final Player[] systemOwners, final boolean shouldClone) { + if (shouldClone) { + this.clonedSystemOwners = systemOwners.clone(); + this.clonedRemainingGarrisons = remainingGarrisons.clone(); + } + + this.systemForces = systemForces; + this.remainingGarrisons = remainingGarrisons; + this.sessionSystemOwners = systemOwners; + } + + public final void advanceAnimationPhase(@MagicConstant(valuesFromClass = AnimationPhase.class) final int phase, + final Collection turnEvents) { + if (turnEvents != null) { + if (phase == AnimationPhase.BUILD) { + final int var13 = this.systemOwners.length; + + for (int var9 = 0; var9 < var13; ++var9) { + this.clonedSystemOwners[var9] = this.systemOwners[var9]; + this.clonedRemainingGarrisons[var9] = this.systemGarrisons[var9]; + } + + for (final TurnEventLog.Event var10 : turnEvents) { + if (var10 instanceof BuildFleetsEvent var16) { + this.clonedRemainingGarrisons[var16.system.index] += var16.quantity; + } else if (var10 instanceof StellarBombEvent var15) { + this.clonedRemainingGarrisons[var15.target.index] -= var15.kill; + } else if (var10 instanceof MoveFleetsOrder var14) { + this.clonedRemainingGarrisons[var14.source.index] -= var14.quantity; + } + } + + this.gameUI.setActionHint(StringConstants.TEXT_ANIMATING_MOVES); + } else if (phase == AnimationPhase.COMBAT) { + for (final TurnEventLog.Event var4 : turnEvents) { + if (var4 instanceof MoveFleetsOrder var5) { + final int var6 = var5.target.index; + if (var5.player == this.systemOwners[var6]) { + this.clonedRemainingGarrisons[var6] += var5.quantity; + } + } + } + + this.random = new IsaacRandom(this.turnSeed); + + for (final CombatEngagementAnimationState var8 : this.combatEngagements) { + var8.reset(); + } + + this.gameUI.setActionHint(StringConstants.TEXT_ANIMATING_COMBAT); + } else if (phase == AnimationPhase.POST_COMBAT) { + for (final CombatEngagementAnimationState var8 : this.combatEngagements) { + final int var9 = var8.system.index; + this.clonedSystemOwners[var9] = var8.victor; + this.clonedRemainingGarrisons[var9] = var8.fleetsAtCombatEnd; + } + + for (final TurnEventLog.Event var10 : turnEvents) { + if (var10 instanceof CombatEngagementLog var12) { + + for (final CombatLogEvent var7 : var12.events) { + if (var7.source != null && var7.source.owner == var7.player) { + this.clonedRemainingGarrisons[var7.source.index] += var7.fleetsRetreated; + } + } + } + } + + this.gameUI.setActionHint(StringConstants.SHOWING_COMBAT_RESULTS); + } else if (phase == AnimationPhase.RETREAT) { + for (final TurnEventLog.Event var4 : turnEvents) { + if (var4 instanceof FleetRetreatEvent var11) { + final int var6 = var11.source.index; + this.clonedSystemOwners[var6] = null; + this.clonedRemainingGarrisons[var6] = 0; + } + } + + this.gameUI.setActionHint(StringConstants.TEXT_ANIMATING_COLLAPSE); + } else if (phase == AnimationPhase.NOT_PLAYING) { + this.assignSystemState(this.remainingGarrisons, this.systemForces, this.sessionSystemOwners, true); + this.gameUI.setActionHint(null); + } + + this.animationPhase = phase; + this.animationTick = 0; + } + } + + protected void a487() { + final int offsetX = JagexApplet.gameWidth / 2; + final int offsetY = this.gameUI.getHeight() / 2; + + if (this.systemHexes == null || this.map.systems.length != this.systemHexes.length) { + final int systemCount = this.map.systems.length; + this.systemDrawX = new int[systemCount]; + this.systemBounds = new Rect[systemCount]; + this.systemDrawY = new int[systemCount]; + this.systemHexes = new int[systemCount][]; + + for (int var5 = 0; var5 < systemCount; ++var5) { + this.systemBounds[var5] = new Rect(); + this.systemHexes[var5] = new int[2 * this.map.systems[var5].hexPoints.length]; + } + } + + this._n = (int) (12000.0F / this.unitScalingFactor); + + for (final StarSystem system : this.map.systems) { + final int i = system.index; + this.systemDrawX[i] = (int) (((float) system.posnX - this.mapScrollPosnX) * 300.0F / ((float) system._z + this.unitScalingFactor)) + offsetX; + this.systemDrawY[i] = (int) (((float) system.posnY - this.mapScrollPosnY) * 300.0F / ((float) system._z + this.unitScalingFactor)) + offsetY; + + for (int j = 0; j < system.hexPoints.length; ++j) { + final Point p = system.hexPoints[j]; + + final float x = (((float) p.x - this.mapScrollPosnX) * 300.0F / this.unitScalingFactor) + offsetX; + final float y = (((float) p.y - this.mapScrollPosnY) * 300.0F / this.unitScalingFactor) + (float) offsetY; + this.systemHexes[i][2 * j] = (int) x; + this.systemHexes[i][2 * j + 1] = (int) y; + + if (x < (float) this.systemBounds[i].x1) { + this.systemBounds[i].x1 = (int) x; + } + if (y < (float) this.systemBounds[i].y1) { + this.systemBounds[i].y1 = (int) y; + } + if (x > (float) this.systemBounds[i].x2) { + this.systemBounds[i].x2 = (int) x; + } + if (y > (float) this.systemBounds[i].y2) { + this.systemBounds[i].y2 = (int) y; + } + } + } + } + + private boolean haveTannhauserEvent(final int phase) { + return this.buildEvents.stream().anyMatch(event -> event.projectType == GameState.ResourceType.EXOTICS && event.phase == phase); + } + + public final Optional setTurnEvents(final TurnEventLog eventLog) { + boolean errorOccurred = false; + final StringBuilder errorMessage = new StringBuilder(); + + this.clearTurnEvents(); + + for (final TurnEventLog.Event event : eventLog.events) { + if (event instanceof MoveFleetsOrder moveOrder) { + if (moveOrder.player == null) { + errorOccurred = true; + errorMessage.append("Fleet from ").append(moveOrder.source.name) + .append(" to ").append(moveOrder.target.name).append(" has no owner.\n"); + } else { + this.fleetMovements.add(new MoveFleetsAnimationState(moveOrder)); + if (moveOrder.quantity > this.largestFleetMovement) { + this.largestFleetMovement = moveOrder.quantity; + } + } + } else if (event instanceof CombatEngagementLog combatLog) { + this.combatEngagements.add(new CombatEngagementAnimationState(combatLog)); + + for (final CombatLogEvent combatEvent : combatLog.events) { + if (combatEvent.source != null && combatEvent.fleetsRetreated != 0 && combatEvent.player == combatEvent.source.owner) { + final MoveFleetsAnimationState moveState = new MoveFleetsAnimationState(new MoveFleetsOrder(combatEvent.player, combatLog.system, combatEvent.source, combatEvent.fleetsRetreated)); + this.combatRetreats.add(moveState); + if (moveState.quantity > this.largestFleetMovement) { + this.largestFleetMovement = moveState.quantity; + } + } + } + } else if (event instanceof ProjectOrder projectEvent) { + if (projectEvent.type == GameState.ResourceType.METAL) { + this.addBuildProjectEvent(projectEvent.target, projectEvent.player, GameState.ResourceType.METAL); + } else if (projectEvent.type == GameState.ResourceType.BIOMASS) { + this.addBuildProjectEvent(projectEvent.target, projectEvent.player, GameState.ResourceType.BIOMASS); + } else if (projectEvent.type == GameState.ResourceType.EXOTICS) { + this.addBuildTannhauserEvent(projectEvent.player, projectEvent.source, projectEvent.target); + } + } else if (event instanceof StellarBombEvent bombEvent) { + this.addBuildProjectEvent(bombEvent.target, bombEvent.player, GameState.ResourceType.ENERGY); + } else if (event instanceof FleetRetreatEvent retreatEvent) { + if (retreatEvent.targets != null) { + for (int i = 0; i < retreatEvent.targets.length; ++i) { + final MoveFleetsOrder moveOrder = new MoveFleetsOrder(retreatEvent.source.lastOwner, retreatEvent.source, retreatEvent.targets[i], retreatEvent.quantities[i]); + final MoveFleetsAnimationState moveState = new MoveFleetsAnimationState(moveOrder); + this.collapseRetreats.add(moveState); + if (moveOrder.quantity > this.largestFleetMovement) { + this.largestFleetMovement = moveOrder.quantity; + } + } + } + this.retreatTargets[retreatEvent.source.index] = true; + } + } + + for (final TurnEventLog.Event event : eventLog.events) { + if (event instanceof BuildFleetsEvent buildEvent) { + if (buildEvent.player == null) { + errorOccurred = true; + errorMessage.append("Build event at ").append(buildEvent.system.name).append(" has no owner.\n"); + } else if (buildEvent.player != this.localPlayer) { + this.addBuildFleetsEvent(buildEvent.system, buildEvent.player, buildEvent.quantity); + if (this.largestFleetBuildQuantity < buildEvent.quantity) { + this.largestFleetBuildQuantity = buildEvent.quantity; + } + } + } + } + + return errorOccurred ? Optional.of(errorMessage.toString()) : Optional.empty(); + } + + @SuppressWarnings("WeakerAccess") + public static final class AnimationPhase { + public static final int NOT_PLAYING = -1; + public static final int BUILD = 0; + public static final int COMBAT = 1; + public static final int POST_COMBAT = 2; + public static final int RETREAT = 3; + } + + public enum SystemHighlight { + NONE, SOURCE, TARGET + } +} diff --git a/src/main/java/funorb/shatteredplans/client/game/BuildEvent.java b/src/main/java/funorb/shatteredplans/client/game/BuildEvent.java new file mode 100644 index 0000000..3f8f6f6 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/BuildEvent.java @@ -0,0 +1,31 @@ +package funorb.shatteredplans.client.game; + +import funorb.shatteredplans.game.Player; +import funorb.shatteredplans.map.StarSystem; + +public final class BuildEvent { + public final StarSystem system; + public final Player player; + public final int projectType; + public final int fleetsBuilt; + public final int phase; + + public BuildEvent(final StarSystem system, + final Player player, + final int projectType, + final int phase) { + this(system, player, projectType, 0, phase); + } + + public BuildEvent(final StarSystem system, + final Player player, + final int projectType, + final int fleetsBuilt, + final int phase) { + this.system = system; + this.player = player; + this.projectType = projectType; + this.fleetsBuilt = fleetsBuilt; + this.phase = phase; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/game/BuildFleetsEvent.java b/src/main/java/funorb/shatteredplans/client/game/BuildFleetsEvent.java new file mode 100644 index 0000000..56a8af9 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/BuildFleetsEvent.java @@ -0,0 +1,16 @@ +package funorb.shatteredplans.client.game; + +import funorb.shatteredplans.game.Player; +import funorb.shatteredplans.map.StarSystem; + +public final class BuildFleetsEvent implements TurnEventLog.Event { + public final Player player; + public final StarSystem system; + public final int quantity; + + public BuildFleetsEvent(final Player player, final StarSystem system, final int quantity) { + this.player = player; + this.system = system; + this.quantity = quantity; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/game/ClientGameSession.java b/src/main/java/funorb/shatteredplans/client/game/ClientGameSession.java new file mode 100644 index 0000000..97195c1 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/ClientGameSession.java @@ -0,0 +1,1895 @@ +package funorb.shatteredplans.client.game; + +import funorb.Strings; +import funorb.awt.KeyState; +import funorb.awt.MouseState; +import funorb.client.lobby.ChatMessage; +import funorb.client.lobby.Component; +import funorb.client.lobby.ContextMenu; +import funorb.io.Buffer; +import funorb.io.CipheredBuffer; +import funorb.shatteredplans.C2SPacket; +import funorb.shatteredplans.S2CPacket; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.GameUI; +import funorb.shatteredplans.client.GameUI.PlacementMode; +import funorb.shatteredplans.client.JagexApplet; +import funorb.shatteredplans.client.Menu; +import funorb.shatteredplans.client.ShatteredPlansClient; +import funorb.shatteredplans.client.Sounds; +import funorb.shatteredplans.client.game.AbstractGameView.SystemHighlight; +import funorb.shatteredplans.game.BuildFleetsOrder; +import funorb.shatteredplans.game.ContiguousForce; +import funorb.shatteredplans.game.Force; +import funorb.shatteredplans.game.GameOptions; +import funorb.shatteredplans.game.GameSession; +import funorb.shatteredplans.game.GameState; +import funorb.shatteredplans.game.MoveFleetsOrder; +import funorb.shatteredplans.game.Player; +import funorb.shatteredplans.game.ProjectOrder; +import funorb.shatteredplans.game.TurnOrders; +import funorb.shatteredplans.game.ai.AI; +import funorb.shatteredplans.game.ai.TaskAI; +import funorb.shatteredplans.game.ai.TutorialAI1; +import funorb.shatteredplans.game.ai.TutorialAI3; +import funorb.shatteredplans.map.Map; +import funorb.shatteredplans.map.StarSystem; +import funorb.util.Functions; +import funorb.util.MathUtil; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public final class ClientGameSession extends GameSession { + private static final int MOUSE_HOLD_DELAY_MAX = 25; + + public static ClientGameSession playSession; + public static ClientGameSession spectateSession; + public static boolean isAutoPlaying = false; + + public final boolean isMultiplayer; + public final boolean isTutorial; + public final boolean isUnrated; + public final GameState gameState; + public int localPlayerIndex; + public Player localPlayer; + public AI[] ais; + public GameUI ui; + public GameView gameView; + private boolean localPlayerIsAlive; + private Player[] systemOwners; + private ContiguousForce[] systemForces; + private int[] remainingGarrisons; + + public boolean desynced; + public int turnNumberWhenJoined; + public TurnEventLog turnEventLog; + public int turnTicksLeft; + public int playersWaitingOn; + public boolean readyToEndTurn = false; + private int leftPlayersBitmap; + private List unsentProjectOrders; + private List unsentBuildOrders; + private List unsentMoveOrders; + private int orderUpdateBusyTimer; + private int orderUpdateIdleTimer; + + public Force selectedForce; // the selected force when building new fleets + private StarSystem selectedSystem; // the system that is selected as the source for an order, like a fleet movement or gate placement + public PlacementMode placementMode; + private boolean rightMouseDown = false; + private boolean rightMouseDragging = false; + private int rightClickX; + private int rightClickY; + private int mouseHoldDelayCounter; + private int mouseHoldDelayAmount = MOUSE_HOLD_DELAY_MAX; + private boolean isDragPanningMap = false; + + private TickTimer recentlyPlayedBuildSfxQueue; + private int recentlyPlayedBuildSfxCounter; + + public boolean[] systemsWillOwn; + private boolean[] systemsCanOwn; + private int[] possibleCollapseStages; + private int[] minGarrisonsAtTurnEnd; + private int[] guaranteedCollapseStages; + private int[] maxGarrisonsAtTurnEnd; + private int[] safeGarrisonsToHold; + private int[] minGarrisonsToHold; + + public ClientGameSession(final boolean isMultiplayer, + final boolean isTutorial, + final int turnLengthIndex, + final @NotNull GameOptions options, + final @NotNull GameState.GameType gameType, + final @NotNull String @NotNull [] playerNames, + final int localPlayerIndex, + final boolean isUnrated, + final @Nullable GameUI ui) { + this.isMultiplayer = isMultiplayer; + this.localPlayerIndex = localPlayerIndex; + this.isTutorial = isTutorial; + this.isUnrated = isUnrated; + if (this.isMultiplayer) { + this.gameState = new GameState(turnLengthIndex, options, gameType, playerNames); + } else if (this.isTutorial) { + this.gameState = TutorialState.createTutorialGameState(turnLengthIndex, options, playerNames); + TutorialState.initialize(this); + } else { + this.gameState = GameState.generate(turnLengthIndex, playerNames, options, gameType); + } + + if (this.isMultiplayer) { + for (int i = 0; i < this.gameState.playerCount; ++i) { + if (playerNames[i].equals("bot_sp")) { + this.gameState.players[i].name = StringConstants.EMPIRE_NAMES[i]; + } + } + } else { + this.gameState.players[0].name = JagexApplet.isAnonymous ? StringConstants.EMPIRE_NAMES[0] : JagexApplet.playerDisplayName; + for (int i = 1; i < this.gameState.playerCount; ++i) { + this.gameState.players[i].name = StringConstants.EMPIRE_NAMES[i]; + } + } + + if (this.localPlayerIndex < 0) { + this.localPlayer = null; + } else { + this.localPlayer = this.gameState.players[this.localPlayerIndex]; + } + + this.localPlayerIsAlive = this.localPlayer != null; + this.ais = new TaskAI[this.gameState.players.length]; + for (final Player player : this.gameState.players) { + player.stats = new PlayerStats(20); + } + + if (this.isTutorial) { + for (int i = 1; i < this.gameState.playerCount; ++i) { + this.ais[i] = new TutorialAI3(this.gameState, this.gameState.players[i], this); + this.ais[i].initialize(false); + } + } else if (!this.isMultiplayer) { + for (int i = 0; i < this.gameState.playerCount; ++i) { + if (i != this.localPlayerIndex) { + this.ais[i] = new TaskAI(this.gameState.players[i], this.gameState, this); + this.ais[i].initialize(true); + } + } + } + + if (ui != null) { + ui.initialize(this); + this.ui = ui; + } + + if (this.isMultiplayer) { + this.unsentProjectOrders = new ArrayList<>(); + this.unsentBuildOrders = new ArrayList<>(); + this.unsentMoveOrders = new ArrayList<>(); + this.orderUpdateIdleTimer = -1; + this.orderUpdateBusyTimer = -1; + this.gameState.setTurnNumber(-1); + } else { + this.initialize(); + this.gameView.targetedSystem = null; + this.gameState.setTurnNumber(0); + this.turnTicksLeft = this.gameState.getTurnDurationTicks(); + } + } + + public void initialize() { + this.gameView = new GameView(this.gameState.map, this.gameState.players, this.localPlayer, this.isTutorial); + if (this.ui == null) { + this.ui = new GameUI(this); + } + this.gameView.setGameUI(this.ui); + + if (!this.isMultiplayer && !this.isTutorial) { + for (int i = 0; i < this.gameState.playerCount; ++i) { + if (this.ais[i] != null) { + this.ais[i].initialize(); + if (ShatteredPlansClient.debugModeEnabled) { + final String message = "My personality is " + StringConstants.AI_TYPES[this.ais[i].getType()]; + this.showChatMessage(this.gameState.players[i], message); + } + } + } + } + + final int systemCount = this.gameState.map.systems.length; + this.systemsCanOwn = new boolean[systemCount]; + this.systemsWillOwn = new boolean[systemCount]; + this.guaranteedCollapseStages = new int[systemCount]; + this.possibleCollapseStages = new int[systemCount]; + this.minGarrisonsAtTurnEnd = new int[systemCount]; + this.safeGarrisonsToHold = new int[systemCount]; + this.maxGarrisonsAtTurnEnd = new int[systemCount]; + this.minGarrisonsToHold = new int[systemCount]; + this.gameState.recalculatePlayerFleetProduction(); + this.gameView.setTacticalOverlay(this.systemsCanOwn, this.systemsWillOwn, this.guaranteedCollapseStages, this.possibleCollapseStages); + + if (this.localPlayerIndex < 0) { + isAutoPlaying = false; + } + if (isAutoPlaying) { + this.ais[this.localPlayerIndex] = new TaskAI(this.localPlayer, this.gameState, this); + } + + for (final Player player : this.gameState.players) { + if (player.contiguousForces.isEmpty()) { + this.gameState.markPlayerDefeated(player.index); + } + } + + this.gameView.resetSystemState(); + this.updateViewStateForTurnStart(); + + for (int i = 0; i < this.gameState.playerCount; ++i) { + if (this.ais[i] != null) { + this.ais[i].makeDesiredPactOffers(); + } + } + + this.recalculateSystemState(); + if (isAutoPlaying || this.localPlayer == null || this.localPlayer.contiguousForces.isEmpty()) { + this.gameView.unitScalingFactor = this.gameView.maxUnitScalingFactor; + } else { + this.gameView.a968(this.localPlayer.contiguousForces.get(0)); + } + + this.gameView.a487(); + } + + public static void updateDrawOfferMenuItem() { + if (playSession.gameState.isPlayerOfferingDraw(playSession.localPlayerIndex)) { + ShatteredPlansClient.MENU_ITEM_LABELS[11] = StringConstants.CANCEL_DRAW; + } else if (playSession.gameState.isAnyoneOfferingDraw()) { + ShatteredPlansClient.MENU_ITEM_LABELS[11] = StringConstants.ACCEPT_DRAW; + } else { + ShatteredPlansClient.MENU_ITEM_LABELS[11] = StringConstants.OFFER_DRAW; + } + } + + private void showChatMessage(final Player player, final String message) { + if (!this.isTutorial) { + final String var4 = player.name + ": "; + int var5 = Component._jiI.width; + if (this.isMultiplayer) { + var5 -= Component.CHAT_FONT.measureLineWidth("[" + Strings.format(StringConstants.XS_GAME, this.gameState.players[0].name) + "] "); + } + + final int var6 = !this.isMultiplayer ? player.color1 : 0; + final int var7 = var5 - Component.CHAT_FONT.measureLineWidth(var4) - 20; + if (var7 < Component.CHAT_FONT.measureLineWidth(message)) { + final String[] obj = GameUI.breakLinesWithColorTags(Component.CHAT_FONT, message, new int[]{var7}); + assert obj != null; + for (final String var11 : obj) { + ContextMenu.showChatMessage(ChatMessage.Channel.ROOM, var4 + var11, var6, JagexApplet.playerDisplayName, this.gameState.players[0].name); + } + } else { + ContextMenu.showChatMessage(ChatMessage.Channel.ROOM, var4 + message, var6, JagexApplet.playerDisplayName, this.gameState.players[0].name); + } + } + } + + private void destroyPlayerForces(final Player player) { + for (final ContiguousForce force : player.contiguousForces) { + for (final StarSystem system : force) { + system.contiguousForce = null; + system.owner = null; + } + } + player.contiguousForces.clear(); + } + + private void readTurnOrders(final CipheredBuffer packet, final int len) { + this.gameState.readTurnOrders(packet, len); + } + + public void handlePlayerLeft(final boolean dueToMouseEvent) { + if (!this.isMultiplayer) { + ShatteredPlansClient.clearChatMessages(); + Menu.switchTo(Menu.Id.MAIN, 0, dueToMouseEvent); + } + ShatteredPlansClient.saveProfile(); + } + + /** + * Recalculates the “hatching” overlay used to display which systems are + * expected or in danger of being captured or lost. + */ + private void recalculateTacticalOverlay() { + for (final StarSystem system : this.gameState.map.systems) { + this.guaranteedCollapseStages[system.index] = 0; + this.possibleCollapseStages[system.index] = 0; + if (system.owner == this.localPlayer) { + this.systemsCanOwn[system.index] = true; + this.maxGarrisonsAtTurnEnd[system.index] = system.remainingGarrison; + this.systemsWillOwn[system.index] = true; + this.minGarrisonsAtTurnEnd[system.index] = system.remainingGarrison; + } else { + this.systemsCanOwn[system.index] = false; + this.maxGarrisonsAtTurnEnd[system.index] = 0; + this.systemsWillOwn[system.index] = false; + this.minGarrisonsAtTurnEnd[system.index] = 0; + } + + for (final MoveFleetsOrder incomingOrder : system.incomingOrders) { + if (incomingOrder.player == this.localPlayer) { + this.maxGarrisonsAtTurnEnd[system.index] += incomingOrder.quantity; + this.systemsCanOwn[system.index] = true; + if (incomingOrder.target.owner == this.localPlayer || incomingOrder.target.garrison == 0) { + this.minGarrisonsAtTurnEnd[system.index] += incomingOrder.quantity; + this.systemsWillOwn[system.index] = true; + } + } + } + + if (this.localPlayer != null) { + for (final StarSystem neighbor : system.neighbors) { + if (neighbor.owner != null && neighbor.owner != this.localPlayer + && (system.owner != this.localPlayer || !neighbor.owner.allies[this.localPlayer.index]) + && !this.isStellarBombTarget(this.localPlayer, neighbor)) { + this.systemsWillOwn[system.index] = false; + this.minGarrisonsAtTurnEnd[system.index] = 0; + break; + } + } + } + } + + if (this.gameState.gameOptions.noChainCollapsing) { + for (final StarSystem system : this.gameState.map.systems) { + this.minGarrisonsToHold[system.index] = 0; + this.safeGarrisonsToHold[system.index] = 0; + } + } else if (this.gameState.gameOptions.simpleGarrisoning) { + for (final StarSystem system : this.gameState.map.systems) { + this.minGarrisonsToHold[system.index] = 1; + this.safeGarrisonsToHold[system.index] = 1; + } + } else { + for (final StarSystem system : this.gameState.map.systems) { + this.minGarrisonsToHold[system.index] = (int) Arrays.stream(system.neighbors).filter(neighbor -> !this.systemsCanOwn[neighbor.index]).count(); + this.safeGarrisonsToHold[system.index] = (int) Arrays.stream(system.neighbors).filter(neighbor -> !this.systemsWillOwn[neighbor.index]).count(); + } + } + + if (!this.gameState.gameOptions.noChainCollapsing) { + boolean goAgain = true; + while (goAgain) { + goAgain = false; + + for (final StarSystem system : this.gameState.map.systems) { + final int index = system.index; + if (this.systemsCanOwn[index] && this.minGarrisonsToHold[index] > this.maxGarrisonsAtTurnEnd[index]) { + goAgain = true; + this.systemsCanOwn[index] = false; + final int nextStage = this.guaranteedCollapseStages[index] + 1; + + for (final StarSystem neighbor : system.neighbors) { + if (this.gameState.gameOptions.simpleGarrisoning) { + this.minGarrisonsToHold[neighbor.index] = 1; + } else { + this.minGarrisonsToHold[neighbor.index]++; + } + + if (this.guaranteedCollapseStages[neighbor.index] > nextStage || this.systemsCanOwn[neighbor.index]) { + this.guaranteedCollapseStages[neighbor.index] = nextStage; + } + } + } + + if (this.systemsWillOwn[index] && this.safeGarrisonsToHold[index] > this.minGarrisonsAtTurnEnd[index]) { + goAgain = true; + this.systemsWillOwn[index] = false; + this.minGarrisonsAtTurnEnd[index] = 0; + final int nextStage = this.possibleCollapseStages[index] + 1; + + for (final StarSystem neighbor : system.neighbors) { + if (this.gameState.gameOptions.simpleGarrisoning) { + this.safeGarrisonsToHold[neighbor.index] = 1; + } else { + this.safeGarrisonsToHold[neighbor.index]++; + } + + if (nextStage < this.possibleCollapseStages[neighbor.index] || this.systemsWillOwn[neighbor.index]) { + this.possibleCollapseStages[neighbor.index] = nextStage; + } + } + } + } + } + } + + this.gameView.setTacticalOverlay(this.systemsCanOwn, this.systemsWillOwn, this.guaranteedCollapseStages, this.possibleCollapseStages); + } + + private void readTurnOrdersAndUpdate(final CipheredBuffer packet, final int len) { + this.readTurnOrders(packet, len); + + for (final BuildFleetsOrder order : this.gameState.buildOrders) { + if (this.gameState.gameOptions.unifiedTerritories) { + order.system.owner.combinedForce.fleetsAvailableToBuild -= order.quantity; + } else { + order.system.contiguousForce.fleetsAvailableToBuild -= order.quantity; + } + order.system.remainingGarrison += order.quantity; + } + + for (final MoveFleetsOrder order : this.gameState.moveOrders) { + order.source.remainingGarrison -= order.quantity; + } + + this.recalculateTacticalOverlay(); + } + + // only used by the tutorial + public void setMap(final Map map) { + this.gameState.setMap(map); + this.gameView.setMap(map); + this.maxGarrisonsAtTurnEnd = new int[map.systems.length]; + this.minGarrisonsToHold = new int[map.systems.length]; + this.systemsCanOwn = new boolean[map.systems.length]; + this.guaranteedCollapseStages = new int[map.systems.length]; + this.minGarrisonsAtTurnEnd = new int[map.systems.length]; + this.safeGarrisonsToHold = new int[map.systems.length]; + this.systemsWillOwn = new boolean[map.systems.length]; + this.possibleCollapseStages = new int[map.systems.length]; + this.recalculateTacticalOverlay(); + } + + public void render() { + this.gameView.render(this.gameState.tannhauserLinks, this.gameState.projectOrders, ShatteredPlansClient.debugModeEnabled && this.desynced); + } + + private void handleRightClickOrderCanceling(final int mouseX, final int mouseY) { + if (JagexApplet.mouseButtonJustClicked == MouseState.Button.RIGHT && !this.rightMouseDown) { + this.rightMouseDown = true; + this.rightClickX = mouseX; + this.rightClickY = mouseY; + this.rightMouseDragging = false; + } else { + if (this.rightMouseDown && JagexApplet.mouseButtonDown == MouseState.Button.RIGHT + && MathUtil.isEuclideanDistanceGreaterThan(this.rightClickX - mouseX, this.rightClickY - mouseY, 5)) { + this.rightMouseDragging = true; + } + + if (this.rightMouseDown && JagexApplet.mouseButtonDown != MouseState.Button.RIGHT) { + this.rightMouseDown = false; + if (!this.rightMouseDragging) { + if (this.placementMode != PlacementMode.NONE) { + Sounds.play(Sounds.SFX_SHIP_SELECTION); + this.ui.setPlacementMode(PlacementMode.NONE); + } else if (this.gameView.targetedSystem != null) { + this.gameState.projectOrders.stream() + .filter(order -> order.player == this.localPlayer && (order.target == this.gameView.targetedSystem || order.source == this.gameView.targetedSystem)) + .toList().forEach(this::cancelProjectOrder); + } + } + } + } + } + + @Override + public void showAIChatMessage(final @NotNull Player sender, + final @NotNull Player recipient, + @MagicConstant(valuesFromClass = StringConstants.AIMessage.class) final int which, + final int systemIndex) { + final Player self = this.isMultiplayer ? this.localPlayer : this.gameState.players[0]; + if (self == recipient) { + final String[] messages = StringConstants.AI_CHAT[which]; + if (messages.length != 0) { + final Player largestPlayer = this.gameState.players[this.gameState.playerFleetProductionRanks[this.gameState.playerCount - 1]]; + final String systemName = systemIndex < this.gameState.map.systems.length ? this.gameState.map.systems[systemIndex].name : ""; + String message = messages[ShatteredPlansClient.randomIntBounded(messages.length)]; + message = Strings.formatNamed(message, "largestplayer", largestPlayer.name); + message = Strings.formatNamed(message, "you", this.localPlayer.name); + message = Strings.formatNamed(message, "me", sender.name); + message = Strings.formatNamed(message, "system", systemName); + this.showChatMessage(sender, message); + } + } + } + + @SuppressWarnings("SameParameterValue") + public boolean handlePacket(final int type, final CipheredBuffer packet, final int len) { + switch (type) { + case S2CPacket.Type.VICTORY: + final byte winnerId = packet.readByte(); + this.gameState.setWinner(winnerId); + this.handleVictory(); + return true; + case S2CPacket.Type.DRAW_OFFERS: + this.gameState.receivePlayersOfferingDrawBitmap(packet.readUByte()); + if (playSession == this) { + updateDrawOfferMenuItem(); + } + return true; + case S2CPacket.Type.RESIGNATIONS: + this.gameState.receiveResignedPlayersBitmap(packet.readUByte()); + return true; + case S2CPacket.Type.REMATCH_OFFERS: + this.gameState.receivePlayersOfferingRematchBitmap(packet.readUByte()); + if (this == playSession) { + ShatteredPlansClient.a150wp(); + } + return true; + case S2CPacket.Type.PLAYERS_LEFT: + this.leftPlayersBitmap = packet.readUByte(); + return true; + case S2CPacket.Type.ADVANCE_TURN: { + final int turnNumber = packet.readUByte(); + final int alliances = packet.readUShort(); + final int turnSeed = packet.readInt(); + final int checksum = packet.readInt(); + final int turnNameIndex2 = packet.readUByte(); + final int turnNameIndex1 = packet.readUByte(); + final int turnTicksLeft = packet.readUShort(); + + this.gameState.setTurnNameIndexes(turnNameIndex1, turnNameIndex2); + if (this.gameState.turnNumber == -1) { + this.gameState.setTurnNumber(turnNumber); + this.tallyPlayerStats(null); + this.turnNumberWhenJoined = this.gameState.turnNumber; + } else if (this.gameState.turnNumber < turnNumber) { + this.tutorialHandleTurnAdvance(); + this.advanceTurnMultiplayer(alliances, turnSeed); + if (checksum == this.gameState.checksum()) { + this.desynced = false; + } else { + C2SPacket.Type.DESYNC.write(C2SPacket.buffer); + C2SPacket.buffer.withLengthShort(() -> { + if (this.localPlayerIndex >= 0) { + this.gameState.writeDesyncReport(C2SPacket.buffer, this.localPlayer); + } + }); + if (!ShatteredPlansClient.debugModeEnabled) { + JagexApplet.flushC2sPacket(0); + JagexApplet.shutdownServerConnection(); + } + this.desynced = true; + isAutoPlaying = false; + } + + this.readyToEndTurn = false; + this.turnTicksLeft = turnTicksLeft; + this.updateViewStateForTurnStart(); + } + + this.turnTicksLeft = turnTicksLeft; + return true; + } + case S2CPacket.Type.TURN_ORDERS: + this.readTurnOrders(packet, len); + return true; + case S2CPacket.Type.DIPLOMATIC_PACTS: + this.readPactUpdates(packet, len); + return true; + case S2CPacket.Type.PLAYERS_WAITING_ON: + this.playersWaitingOn = packet.readUByte(); + return true; + case S2CPacket.Type.TURN_ORDERS_AND_UPDATE: + this.readTurnOrdersAndUpdate(packet, len); + return true; + case S2CPacket.Type.RESEND_ALL_TURN_ORDERS: + this.resendAllTurnOrders(); + return true; + case S2CPacket.Type.AI_CHAT: { + final int senderIndex = packet.readUByte(); + @MagicConstant(valuesFromClass = StringConstants.AIMessage.class) + final int which = packet.readUByte(); + final int systemIndex = packet.readUByte(); + this.showAIChatMessage(this.gameState.players[senderIndex], this.localPlayer, which, systemIndex); + return true; + } + case 74: + if (ShatteredPlansClient.debugModeEnabled) { + final int var2 = len / 4; + for (int i = 0; i < var2; ++i) { + final int var4 = packet.readUByte(); + final int var5 = packet.readUByte(); + final int var6 = packet.readUShort(); + final String var12 = "My personality type is " + StringConstants.AI_TYPES[var5] + " and my rating is " + var6; + this.showChatMessage(this.gameState.players[var4], var12); + } + return true; + } else { + return false; + } + default: + return false; + } + } + + private void handleVictory() { + Menu.switchTo(Menu.Id.GAME, 0, false); + this.localPlayerIsAlive = false; + this.ui.handleVictory(); + if ((this.localPlayer != null && this.gameState.isPlayerDefeated(this.localPlayerIndex)) || this.gameState.victoryChecker.isLoser(this.localPlayer)) { + ShatteredPlansClient.a827jo(Sounds.MUSIC_LOSE, 10, false); + } else if (this.gameState.hasEnded) { + ShatteredPlansClient.a827jo(Sounds.MUSIC_WIN, 10, false); + } +// if (isAutoPlaying && !this.gameState.isPlayerOfferingRematch(this.localPlayerIndex)) { +// this.offerRematch(); +// } + isAutoPlaying = false; + } + + private void simulateTurn(final int seed) { + this.turnEventLog = new TurnEventLog(); + this.gameView.resetSystemState(); + final int[] playerFleetProduction = this.tallyPlayerFleetProduction(); + this.gameState.simulateTurn(this.turnEventLog, seed); + + final Optional maybeError = this.gameView.setTurnEvents(this.turnEventLog); + this.gameState.resetTurnState(); + this.tallyPlayerStats(playerFleetProduction); + maybeError.ifPresent(errorMessage -> { + JagexApplet.clientError(null, errorMessage); + JagexApplet.shutdownServerConnection(); + }); + + if (this.isTutorial) { + if (this.gameState.isPlayerDefeated(this.localPlayerIndex)) { + TutorialState.a984fl("losegame"); + } else if (this.gameState.victoryChecker.isLoser(this.localPlayer)) { + TutorialState.a984fl("wingame"); + } + } + } + + public void sendResign() { + if (this.isMultiplayer) { + C2SPacket.Type.RESIGN.write(C2SPacket.buffer); + } else { + throw new IllegalStateException(); + } + } + + private void processInput() { + boolean mouseHandled = false; + if (this.ui.processInput(true)) { + this.rightMouseDragging = true; + mouseHandled = true; + this.rightMouseDown = false; + this.gameView._nb[1] = -1; + this.gameView._nb[0] = -1; + this.gameView.targetedSystem = null; + this.gameView.selectedFleetOrder = null; + } else { + if (JagexApplet.mouseButtonJustClicked == MouseState.Button.LEFT) { + this.handleLeftClick(JagexApplet.mousePressX, JagexApplet.mousePressY); + } + + this.handleRightClickOrderCanceling(JagexApplet.mouseX, JagexApplet.mouseY); + this.gameView.a115(this.placementMode, JagexApplet.mouseX, JagexApplet.mouseY); + } + + float var3 = this.gameView.mapScrollPosnX; + float var4 = this.gameView.mapScrollPosnY; + if (JagexApplet.keysDown[96]) { + var3 -= 5.0F * (this.gameView.unitScalingFactor + 50.0F) / 300.0F; + if (var3 < 0.0F) { + var3 = 0.0F; + } + } + + float var5 = this.gameView.unitScalingFactor; + if (JagexApplet.keysDown[97]) { + var3 += 5.0F * (this.gameView.unitScalingFactor + 50.0F) / 300.0F; + if ((float) (this.gameState.map.drawingWidth) < var3) { + var3 = (float) (this.gameState.map.drawingWidth); + } + } + + if (JagexApplet.keysDown[98]) { + var4 -= 5.0F * (this.gameView.unitScalingFactor + 50.0F) / 300.0F; + if (var4 < 0.0F) { + var4 = 0.0F; + } + } + + if (JagexApplet.keysDown[99]) { + var4 += 5.0F * (this.gameView.unitScalingFactor + 50.0F) / 300.0F; + if ((float) (this.gameState.map.drawingHeight) < var4) { + var4 = (float) (this.gameState.map.drawingHeight); + } + } + + if (JagexApplet.keysDown[27] || JagexApplet.keysDown[87]) { + var5 /= 1.1F; + if (var5 < AbstractGameView.TWO_HUNDRED_F) { + var5 = AbstractGameView.TWO_HUNDRED_F; + } + } + + if (JagexApplet.keysDown[26] || JagexApplet.keysDown[88]) { + var5 *= 1.1F; + if (var5 > this.gameView.maxUnitScalingFactor) { + var5 = this.gameView.maxUnitScalingFactor; + } + } + + if (mouseHandled || JagexApplet.mouseButtonDown != MouseState.Button.RIGHT) { + this.isDragPanningMap = false; + } else { + if (this.isDragPanningMap) { + final int var6 = JagexApplet.mouseX - this.gameView.lastTickMouseX; + final int var7 = JagexApplet.mouseY - this.gameView.lastTickMouseY; + var3 -= this.gameView.unitScalingFactor * (float) var6 / 300.0F; + if (var3 < 0.0F) { + var3 = 0.0F; + } + + var4 -= (float) var7 * this.gameView.unitScalingFactor / 300.0F; + if (var3 > (float) (this.gameState.map.drawingWidth)) { + var3 = (float) (this.gameState.map.drawingWidth); + } + + if (var4 < 0.0F) { + var4 = 0.0F; + } + + if (var4 > (float) (this.gameState.map.drawingHeight)) { + var4 = (float) (this.gameState.map.drawingHeight); + } + } + + this.gameView.lastTickMouseX = JagexApplet.mouseX; + this.gameView.lastTickMouseY = JagexApplet.mouseY; + this.isDragPanningMap = true; + } + + if (!mouseHandled && JagexApplet.mouseWheelRotation != 0) { + final short var11 = 320; + final int var7 = this.ui.getHeight() / 2; + final float var8 = var3 + (float) (JagexApplet.mouseX - var11) * this.gameView.unitScalingFactor / 300.0F; + final float var9 = (float) (JagexApplet.mouseY - var7) * this.gameView.unitScalingFactor / 300.0F + var4; + int var10; + if (JagexApplet.mouseWheelRotation <= 0) { + for (var10 = 2 * JagexApplet.mouseWheelRotation; var10 < 0; ++var10) { + var5 /= 1.1F; + } + + if (!JagexApplet.DEBUG_MODE && var5 < AbstractGameView.TWO_HUNDRED_F) { + var5 = AbstractGameView.TWO_HUNDRED_F; + } + } else { + for (var10 = 0; JagexApplet.mouseWheelRotation * 2 > var10; ++var10) { + var5 *= 1.1F; + } + + if (var5 > this.gameView.maxUnitScalingFactor) { + var5 = this.gameView.maxUnitScalingFactor; + } + } + + var3 = var8 - var5 * (float) (-320 + JagexApplet.mouseX) / 300.0F; + var4 = var9 - var5 * (float) (JagexApplet.mouseY - var7) / 300.0F; + if (var3 < 0.0F) { + var3 = 0.0F; + } + + if (var4 < 0.0F) { + var4 = 0.0F; + } + + if ((float) (this.gameState.map.drawingWidth) < var3) { + var3 = (float) (this.gameState.map.drawingWidth); + } + + if (var4 > (float) (this.gameState.map.drawingHeight)) { + var4 = (float) (this.gameState.map.drawingHeight); + } + } + + if (this.gameView.mapScrollPosnX != var3 || this.gameView.mapScrollPosnY != var4 || this.gameView.unitScalingFactor != var5) { + this.gameView.unitScalingFactor = var5; + this.gameView.isAnimatingViewport = false; + this.gameView._fb = null; + this.gameView.mapScrollPosnY = var4; + this.gameView.mapScrollPosnX = var3; + this.gameView.a487(); + } + + if (JagexApplet.mouseButtonDown == MouseState.Button.NONE) { + this.mouseHoldDelayAmount = MOUSE_HOLD_DELAY_MAX; + this.mouseHoldDelayCounter = 0; + } else if (this.gameView.selectedFleetOrder != null) { + this.processInputFleetOrder(this.gameView.selectedFleetOrder); + } + + this.gameView.c326(); + } + + private void sendOutstandingOrders(@SuppressWarnings("SameParameterValue") final CipheredBuffer packet) { + C2SPacket.Type.ORDERS.write(packet); + packet.withLengthShort(() -> { + packet.writeByte(this.gameState.turnNumber); + TurnOrders.write(packet, + this.unsentProjectOrders, + this.unsentBuildOrders, + this.unsentMoveOrders); + }); + this.unsentProjectOrders.clear(); + this.unsentBuildOrders.clear(); + this.unsentMoveOrders.clear(); + this.orderUpdateBusyTimer = -1; + this.orderUpdateIdleTimer = -1; + if (isAutoPlaying) { + this.endTurn(); + } + } + + @MagicConstant(intValues = {0, KeyState.Code.SHIFT, KeyState.Code.ALT, KeyState.Code.CONTROL}) + private int getModifierKey() { + int modifierCode = 0; + + if (JagexApplet.keysDown[KeyState.Code.SHIFT]) { + modifierCode = KeyState.Code.SHIFT; + } + + if (JagexApplet.keysDown[KeyState.Code.ALT]) { + if (modifierCode == 0) { + modifierCode = KeyState.Code.ALT; + } else { + return 0; + } + } + + if (JagexApplet.keysDown[KeyState.Code.CONTROL]) { + if (modifierCode == 0) { + modifierCode = KeyState.Code.CONTROL; + } else { + return 0; + } + } + + return modifierCode; + } + + public void offerRematch() { + if (this.isMultiplayer) { + this.gameState.setPlayerOfferingRematch(this.localPlayerIndex); + C2SPacket.Type.OFFER_REMATCH.write(C2SPacket.buffer); + } else { + throw new IllegalStateException(); + } + } + + private void processInputFleetOrder(final MoveFleetsOrder order) { + if (order.player != this.localPlayer) return; + if (this.mouseHoldDelayCounter > 0) { + --this.mouseHoldDelayCounter; + return; + } + + if (JagexApplet.mouseButtonDown == MouseState.Button.LEFT && order != this.gameView._rb) { + this.gameView.b423(); + } + + if (JagexApplet.mouseButtonDown == MouseState.Button.LEFT && this.gameView._Ab) { + int var3 = 1; + final int modifier = this.getModifierKey(); + final StarSystem var5 = this.gameView.selectedFleetOrder.source; + if (modifier == KeyState.Code.CONTROL) { + var3 = var5.minimumGarrison >= var5.remainingGarrison ? var5.remainingGarrison : var5.remainingGarrison - var5.minimumGarrison; + } else if (modifier == KeyState.Code.ALT) { + var3 = 5; + } + + final int var6 = this.gameState.gameOptions.garrisonsCanBeRemoved ? 0 : var5.minimumGarrison; + if (var5.remainingGarrison - var6 < var3) { + var3 = var5.remainingGarrison - var6; + } + + if (var3 <= 0) { + Sounds.play(Sounds.SFX_SHIP_ATTACK_ORDER); + } else { + this.addToMoveOrder(this.gameView.selectedFleetOrder, var3); + } + } else if (JagexApplet.mouseButtonDown == MouseState.Button.LEFT && this.gameView._Gb) { + int var3 = -1; + final int modifier = this.getModifierKey(); + if (modifier == KeyState.Code.CONTROL) { + var3 = -this.gameView.selectedFleetOrder.quantity; + } else if (modifier == KeyState.Code.ALT) { + var3 = -(Math.min(5, this.gameView.selectedFleetOrder.quantity)); + } + + this.addToMoveOrder(this.gameView.selectedFleetOrder, var3); + if (this.gameView.selectedFleetOrder.quantity == 0) { + this.gameView._nb[1] = -1; + this.gameView._nb[0] = -1; + this.gameView.selectedFleetOrder = null; + this.gameView.b423(); + } + } else if (JagexApplet.mouseButtonDown == MouseState.Button.LEFT && this.gameView._Bb) { + final int var3 = -order.quantity; + this.addToMoveOrder(this.gameView.selectedFleetOrder, var3); + this.gameView._nb[1] = -1; + this.gameView.selectedFleetOrder = null; + this.gameView._nb[0] = -1; + this.gameView.b423(); + } + + this.mouseHoldDelayAmount -= 5; + if (this.mouseHoldDelayAmount < 0) { + this.mouseHoldDelayAmount = 0; + } + + this.mouseHoldDelayCounter = this.mouseHoldDelayAmount; + this.recalculateSystemState(); + } + + public void recalculateSystemState() { + if (this.systemOwners.length < this.gameState.map.systems.length) { + this.systemOwners = new Player[this.gameState.map.systems.length]; + this.remainingGarrisons = new int[this.gameState.map.systems.length]; + this.systemForces = new ContiguousForce[this.gameState.map.systems.length]; + } + + for (final StarSystem system : this.gameState.map.systems) { + final int i = system.index; + this.systemOwners[i] = system.owner; + this.remainingGarrisons[i] = system.owner == this.localPlayer ? system.remainingGarrison : system.garrison; + this.systemForces[i] = system.contiguousForce; + } + + this.gameView.assignSystemState(this.remainingGarrisons, this.systemForces, this.systemOwners, true); + } + + public void endTurn() { + if (this.isMultiplayer) { + if (this.orderUpdateIdleTimer != -1) { + this.sendOutstandingOrders(C2SPacket.buffer); + } + + this.sendEndTurn(); + this.readyToEndTurn = true; + if (this.playersWaitingOn > 1) { + --this.playersWaitingOn; + } + } else { + this.advanceTurnSinglePlayer(); + } + } + + private void sendEndTurn() { + C2SPacket.Type.END_TURN.write(C2SPacket.buffer); + C2SPacket.buffer.writeByte(this.gameState.turnNumber); + C2SPacket.buffer.writeInt(this.gameState.ordersChecksum()); + } + + private void cancelEndTurn() { + C2SPacket.Type.CANCEL_END_TURN.write(C2SPacket.buffer); + C2SPacket.buffer.writeByte(this.gameState.turnNumber); + } + + private void handlePactOffer(final Player offerer, final Player offeree) { + this.getAI(offeree).ifPresent(ai -> ai.handlePactOffer(offerer)); + } + + private void playerIssuedOrder() { + if (this.readyToEndTurn) { + this.cancelEndTurn(); + this.readyToEndTurn = false; + } + + if (this.orderUpdateBusyTimer == -1) { + this.orderUpdateBusyTimer = 250; + } + + this.orderUpdateIdleTimer = 25; + } + + private void advanceTurnMultiplayer(final int alliances, final int seed) { + this.gameState.recalculateFleetsRemaining(); + this.gameState.setAlliancesBitmap(alliances); + this.simulateTurn(seed); + this.gameView.turnSeed = seed; + } + + private void readPactUpdates(final Buffer packet, int len) { + while (len > 0) { + final int type = packet.readUByte(); + --len; + if (type == 0) { + final int offers = packet.readUByte(); + final int newOffers = ~this.localPlayer.incomingPactOffersBitmap & offers; + this.localPlayer.incomingPactOffersBitmap = offers; + --len; + if (newOffers == 0) { + continue; + } + + for (int i = 0; i < this.gameState.playerCount; ++i) { + if ((newOffers & (1 << i)) != 0) { + this.handlePactOffer(this.gameState.players[i], this.localPlayer); + } + } + } else if (type == 1) { + final int offererIndex = packet.readUByte(); + final int offereeIndex = packet.readUByte(); + final Player offerer = this.gameState.players[offererIndex]; + final Player offeree = this.gameState.players[offereeIndex]; + JagexApplet.printDebug("RECV PACT " + offerer + " <-> " + offeree); + Player.establishPact(offerer, offeree); + this.handlePactAccepted(offerer, offeree); + len -= 3; + } + } + } + + private void tallyPlayerStats(final int[] playerFleetProduction) { + final int[] var3 = new int[this.gameState.playerCount]; + final int[] var4 = new int[this.gameState.playerCount]; + final int[] var5 = new int[this.gameState.playerCount]; + final int[] var6 = new int[this.gameState.playerCount]; + final int[] var7 = new int[this.gameState.playerCount]; + final int[] var8 = new int[this.gameState.playerCount]; + final int[] var9 = new int[this.gameState.playerCount]; + final int[] var10 = new int[this.gameState.playerCount]; + + for (final StarSystem system : this.gameState.map.systems) { + if (system.owner != null) { + var3[system.owner.index] += system.garrison; + var6[system.owner.index]++; + if (system.resources[0] >= 0) { + for (int i = 0; i < GameState.NUM_RESOURCES; ++i) { + var5[system.owner.index] += system.resources[i]; + } + } + } + } + + for (final Player value : this.gameState.players) { + if (!this.gameState.gameOptions.unifiedTerritories) { + for (final ContiguousForce var28 : value.contiguousForces) { + var4[value.index] += var28.fleetProduction; + } + } else if (value.combinedForce != null) { + var4[value.index] = value.combinedForce.fleetProduction; + } + } + + if (this.turnEventLog != null) { + for (final TurnEventLog.Event event : this.turnEventLog.events) { + if (event instanceof BuildFleetsEvent buildEvent) { + if (buildEvent.player != null) { + var7[buildEvent.player.index] += buildEvent.quantity; + } + } + + if (event instanceof CombatEngagementLog combatLog) { + for (int i = 0; i < this.gameState.playerCount; ++i) { + var8[i] += combatLog.playerKills[i]; + } + + if (combatLog.victor == combatLog.ownerAtCombatStart) { + if (combatLog.victor != null) { + ++combatLog.victor.stats._y; + } + + for (final Player player : combatLog.players) { + if (player != null && player != combatLog.ownerAtCombatStart) { + ++player.stats._q; + } + } + } else { + if (combatLog.ownerAtCombatStart != null) { + ++combatLog.ownerAtCombatStart.stats._a; + } + + if (combatLog.victor != null) { + ++combatLog.victor.stats._m; + } + + for (final Player player : combatLog.players) { + if (player != null && combatLog.ownerAtCombatStart != player && combatLog.victor != player) { + ++player.stats._q; + } + } + } + + for (final CombatLogEvent combatEvent : combatLog.events) { + if (combatLog.ownerAtCombatStart != combatEvent.player) { + var10[combatEvent.player.index] += combatEvent.fleetsAtStart; + } + } + } + + if (event instanceof StellarBombEvent bombEvent) { + var8[bombEvent.player.index] += bombEvent.kill; + ++bombEvent.player.stats._s; + } + + if (event instanceof ProjectOrder projectOrder) { + ++projectOrder.player.stats._s; + } + + if (event instanceof MoveFleetsOrder moveOrder) { + moveOrder.player.stats._t++; + moveOrder.player.stats._i += moveOrder.quantity; + var9[moveOrder.player.index] += moveOrder.quantity; + } + } + } + + final int turnIndex = this.gameState.turnNumber != -1 ? this.gameState.turnNumber % 100 : 0; + for (int i = 0; i < this.gameState.playerCount; ++i) { + final Player player = this.gameState.players[i]; + player.stats.fleets[turnIndex] = var3[i]; + player.stats.production[turnIndex] = var4[i]; + player.stats.systems[turnIndex] = var6[i]; + if (var3[i] > player.stats._A) { + player.stats._A = var3[i]; + } + + player.stats._v += var8[i]; + if (var4[i] > player.stats._x) { + player.stats._x = var4[i]; + } + + player.stats._o += var7[i]; + player.stats._r = player.stats._e + (player.stats._o - var3[i]); + if (!player.contiguousForces.isEmpty()) { + if (playerFleetProduction != null) { + if (var5[i] > 0) { + player.stats._u += (var4[i] * 800 + var5[i]) / (var5[i] * 2); + } + player.stats._z += (playerFleetProduction[i] + 200 * var10[i]) / (2 * playerFleetProduction[i]); + player.stats._w += (playerFleetProduction[i] + 200 * var9[i]) / (2 * playerFleetProduction[i]); + } + player.stats._l = this.gameState.turnNumber - this.turnNumberWhenJoined; + } + } + } + + @Override + public void handleAIPactOffer(final @NotNull Player offerer, final @NotNull Player offeree) { + if (this.isMultiplayer) { + if (isAutoPlaying) { + this.requestOrAcceptPact(offeree); + } else { + throw new RuntimeException(); + } + } + super.handleAIPactOffer(offerer, offeree); + } + + public void sendOfferDraw() { + if (this.isMultiplayer) { + C2SPacket.Type.OFFER_DRAW.write(C2SPacket.buffer); + } else { + throw new IllegalStateException(); + } + } + + public void addTutorialAIPlayer(final Player player) { + this.gameState.addPlayer(player); + final TutorialAI1 var3 = new TutorialAI1(this.gameState, player, this); + final TutorialAI1[] ais = new TutorialAI1[this.ais.length + 1]; + + for (int i = 0; i < this.ais.length; ++i) { + if (this.ais[i] != null) { + ais[i] = new TutorialAI1(this.gameState, this.gameState.players[i], this); + final TutorialAI1 var6 = (TutorialAI1) this.ais[i]; + System.arraycopy(var6._i, 0, ais[i]._i, 0, var6._i.length); + } + } + ais[player.index] = new TutorialAI1(this.gameState, player, this); + ais[this.ais.length] = var3; + this.ais = ais; + } + + public void handleKeyTyped() { + if (this.isMultiplayer) { + if (this.localPlayerIndex >= 0 ? ShatteredPlansClient.isChatboxSelected : (JagexApplet.lastTypedKeyCode != KeyState.Code.ESCAPE && GameUI._gen)) { + return; + } + } + + if (JagexApplet.lastTypedKeyCode == KeyState.Code.ESCAPE) { + @MagicConstant(valuesFromClass = Menu.Id.class) + int var8 = Menu.Id.PAUSE_SINGLEPLAYER; + if (this.isMultiplayer) { + if (this.localPlayerIndex < 0) { + var8 = Menu.Id.PAUSE_MULTIPLAYER_3; + } else if (this.localPlayerIsAlive) { + var8 = Menu.Id.PAUSE_MULTIPLAYER_1; + } else { + var8 = Menu.Id.PAUSE_MULTIPLAYER_2; + } + } + Menu.switchTo(var8, 0, false); + } else { + this.ui.h150(); + if (ShatteredPlansClient.debugModeEnabled && !this.isMultiplayer) { + if (JagexApplet.keysDown[KeyState.Code.ALT] && JagexApplet.keysDown[KeyState.Code.LETTER_R]) { + this.destroyPlayerForces(this.localPlayer); + this.endTurn(); + } else if (JagexApplet.keysDown[KeyState.Code.ALT] && JagexApplet.keysDown[KeyState.Code.LETTER_V]) { + for (final Player player : this.gameState.players) { + if (player != this.localPlayer) { + this.destroyPlayerForces(player); + } + } + this.endTurn(); + } + } + + if (ShatteredPlansClient.debugModeEnabled && this.isMultiplayer && this.localPlayer != null) { + if (JagexApplet.keysDown[KeyState.Code.CONTROL] && JagexApplet.keysDown[KeyState.Code.SHIFT] && JagexApplet.lastTypedKeyCode == KeyState.Code.NUMBER_1) { + this.autoPlanTurn(); + } else if (JagexApplet.keysDown[KeyState.Code.CONTROL] && JagexApplet.keysDown[KeyState.Code.SHIFT] && JagexApplet.lastTypedKeyCode == KeyState.Code.NUMBER_2) { + this.autoPlanTurn(); + isAutoPlaying = false; + this.ais[this.localPlayerIndex] = null; + } + } + } + } + + private void autoPlanTurn() { + if (this.localPlayer == null) { + throw new IllegalStateException("cannot plan turn without a local player"); + } + + isAutoPlaying = true; + + for (final MoveFleetsOrder order : this.gameState.moveOrders) { + this.cancelMoveOrder(order); + } + for (final BuildFleetsOrder order : this.gameState.buildOrders) { + this.cancelBuildOrder(order); + } + for (final ProjectOrder order : this.gameState.projectOrders) { + this.cancelProjectOrder(order); + } + this.playerIssuedOrder(); + + final TaskAI ai = new TaskAI(this.localPlayer, this.gameState, this); + this.ais[this.localPlayerIndex] = ai; + + ai.makeDesiredPactOffers(); + for (final Player player : this.gameState.players) { + if (player != this.localPlayer && this.localPlayer.hasPactOfferFrom(player)) { + ai.handlePactOffer(player); + } + } + final TurnOrders orders = ai.planAndGetTurnOrders(); + for (final StarSystem system : this.gameState.map.systems) { + system.remainingGarrison = system.garrison; + } + this.addOrders(orders); + + this.recalculateSystemState(); + + this.unsentMoveOrders.addAll(this.gameState.moveOrders); + this.unsentBuildOrders.addAll(this.gameState.buildOrders); + this.unsentProjectOrders.addAll(this.gameState.projectOrders); + this.playerIssuedOrder(); + } + + private void handleLeftClick(final int x, final int y) { + this.gameView.a115(this.placementMode, x, y); + if (this.localPlayerIsAlive) { + if (this.gameView.targetedSystem != null) { + if (this.placementMode == PlacementMode.MOVE_FLEET_SRC) { + if (this.localPlayer != null + && this.gameView.targetedSystem.owner == this.localPlayer + && this.gameView.targetedSystem.remainingGarrison > 0) { + this.selectedSystem = this.gameView.targetedSystem; + Sounds.play(Sounds.SFX_SHIP_SELECTION); + this.ui.setPlacementMode(PlacementMode.MOVE_FLEET_DEST); + + this.gameView.highlightedSystems[this.selectedSystem.index] = SystemHighlight.SOURCE; + for (final StarSystem neighbor : this.selectedSystem.neighbors) { + if (neighbor.owner == null || !this.localPlayer.allies[neighbor.owner.index]) { + this.gameView.highlightedSystems[neighbor.index] = SystemHighlight.TARGET; + } + } + for (final StarSystem system : this.selectedSystem.contiguousForce) { + if (system != this.selectedSystem && this.gameState.movementInRange(this.selectedSystem, system)) { + this.gameView.highlightedSystems[system.index] = SystemHighlight.TARGET; + } + } + } + } else if (this.placementMode == PlacementMode.MOVE_FLEET_DEST) { + final StarSystem source = this.selectedSystem; + final StarSystem target = this.gameView.targetedSystem; + + if ((source.hasNeighbor(target) && (target.owner == null || !this.localPlayer.allies[target.owner.index])) + || ((source != target) + && (source.contiguousForce == target.contiguousForce) + && this.gameState.movementInRange(source, target))) { + this.gameView.stopCombatAnimations(); + final int spareFleets = source.remainingGarrison - source.minimumGarrison; + int fleetsToMove = spareFleets <= 0 ? 1 : (1 + spareFleets) / 2; + final int modifier = this.getModifierKey(); + if (modifier == KeyState.Code.SHIFT) { + fleetsToMove = 1; + } else if (modifier == KeyState.Code.ALT) { + fleetsToMove = 5; + } else if (modifier == KeyState.Code.CONTROL) { + if (spareFleets <= 0) { + fleetsToMove = source.remainingGarrison; + } else { + fleetsToMove = spareFleets; + } + } + + final int immovableFleets = this.gameState.gameOptions.garrisonsCanBeRemoved ? 0 : source.minimumGarrison; + if (fleetsToMove > source.remainingGarrison - immovableFleets) { + fleetsToMove = source.remainingGarrison - immovableFleets; + } + + if (fleetsToMove > 0) { + this.handleMoveFleets(source, target, fleetsToMove); + if (target.owner == this.localPlayer + || target.owner == null && target.garrison == 0) { + Sounds.play(Sounds.SFX_SHIP_MOVE_ORDER); + } else { + Sounds.play(Sounds.SFX_SHIP_ATTACK_ORDER); + } + } + + this.recalculateSystemState(); + } + + this.ui.setPlacementMode(PlacementMode.NONE); + } else if (this.placementMode == PlacementMode.BUILD_FLEET) { + if (this.gameView.targetedSystem.contiguousForce == this.selectedForce + || this.gameState.gameOptions.unifiedTerritories + && this.gameView.targetedSystem.owner != null + && this.gameView.targetedSystem.owner.combinedForce == this.selectedForce) { + this.gameView.stopCombatAnimations(); + this.handleBuildFleets(this.gameView.targetedSystem); + if (this.recentlyPlayedBuildSfxCounter > 3) { + final int var5 = this.recentlyPlayedBuildSfxCounter - 3; + int volume = 0x60 >> (var5 >> 1); + if ((var5 & 1) != 0) { + volume = (0xb505 * volume) >> 16; + } + if (volume < 24) { + volume = 24; + } + Sounds.play(Sounds.SFX_FACTORY_NOISE, volume); + } else { + Sounds.play(Sounds.SFX_FACTORY_NOISE); + } + + if (this.recentlyPlayedBuildSfxQueue == null) { + this.recentlyPlayedBuildSfxQueue = new TickTimer(ShatteredPlansClient.currentTick); + } else { + this.recentlyPlayedBuildSfxQueue.addNext(ShatteredPlansClient.currentTick); + } + + ++this.recentlyPlayedBuildSfxCounter; + this.recalculateSystemState(); + } + } else if (this.placementMode == PlacementMode.DEFENSIVE_NET) { + if (this.gameView.targetedSystem.owner == this.localPlayer && !this.gameView.targetedSystem.hasDefensiveNet) { + this.gameView.stopCombatAnimations(); + this.recalculateSystemState(); + this.handleBuildProject(GameState.ResourceType.METAL, this.gameView.targetedSystem); + this.ui.setPlacementMode(PlacementMode.NONE); + this.ui.markProjectPending(GameState.ResourceType.METAL); + } + } else if (this.placementMode == PlacementMode.TERRAFORM) { + if (this.gameView.targetedSystem.owner == this.localPlayer && this.gameView.targetedSystem.score == StarSystem.Score.NORMAL) { + this.gameView.stopCombatAnimations(); + this.recalculateSystemState(); + this.handleBuildProject(GameState.ResourceType.BIOMASS, this.gameView.targetedSystem); + this.ui.setPlacementMode(PlacementMode.NONE); + this.ui.markProjectPending(GameState.ResourceType.BIOMASS); + } + } else if (this.placementMode == PlacementMode.STELLAR_BOMB) { + final StarSystem target = this.gameView.targetedSystem; + final boolean ownsNeighboring = Arrays.stream(target.neighbors) + .anyMatch(neighbor -> neighbor.owner == this.localPlayer); + final boolean isNotAllied = target.owner == null || !this.localPlayer.allies[target.owner.index]; + if (ownsNeighboring && target.owner != this.localPlayer && isNotAllied) { + this.gameView.stopCombatAnimations(); + this.recalculateSystemState(); + this.handleBuildProject(GameState.ResourceType.ENERGY, target); + this.recalculateTacticalOverlay(); + this.ui.setPlacementMode(PlacementMode.NONE); + this.ui.markProjectPending(GameState.ResourceType.ENERGY); + } + } else if (this.placementMode == PlacementMode.GATE_SRC) { + if (this.gameView.targetedSystem.owner == this.localPlayer) { + this.gameView.stopCombatAnimations(); + this.recalculateSystemState(); + this.selectedSystem = this.gameView.targetedSystem; + this.ui.setPlacementMode(PlacementMode.GATE_DEST); + + for (final StarSystem system : this.gameState.map.systems) { + if (system != this.gameView.targetedSystem && !this.gameView.targetedSystem.hasNeighbor(system)) { + this.gameView.highlightedSystems[system.index] = SystemHighlight.TARGET; + } + } + } + } else if (this.placementMode == PlacementMode.GATE_DEST) + if (!this.selectedSystem.hasNeighbor(this.gameView.targetedSystem) && this.selectedSystem != this.gameView.targetedSystem) { + this.gameView.stopCombatAnimations(); + this.recalculateSystemState(); + this.handleBuildProject(this.gameView.targetedSystem, this.selectedSystem); + this.ui.setPlacementMode(PlacementMode.NONE); + this.ui.markProjectPending(GameState.ResourceType.EXOTICS); + } + } + } + } + + private void advanceTurnSinglePlayer() { + this.tutorialHandleTurnAdvance(); + + if (++this.localPlayerIndex == this.gameState.players.length) { + this.localPlayer = this.gameState.players[0]; + this.localPlayerIndex = 0; + this.gameState.recalculateFleetsRemaining(); + this.simulateTurn(ShatteredPlansClient.globalRandom.nextInt()); + this.gameView.turnSeed = ShatteredPlansClient.globalRandom.nextInt(); + this.gameState.generateNewTurnName(); + + for (int i = 0; i < this.gameState.playerCount; ++i) { + if (this.ais[i] != null) { + this.ais[i].makeDesiredPactOffers(); + } + } + } + + this.localPlayer = this.gameState.players[this.localPlayerIndex]; + this.turnTicksLeft = this.gameState.getTurnDurationTicks(); + this.updateViewStateForTurnStart(); + } + + public void cancelProjectOrder(@MagicConstant(valuesFromClass = GameState.ResourceType.class) final int type) { + this.gameState.projectOrders.stream() + .filter(order -> order.type == type) + .findFirst() + .ifPresent(this::cancelProjectOrder); + } + + private void cancelProjectOrder(final ProjectOrder order) { + order.source = null; + order.target = null; + if (this.isMultiplayer) { + this.unsentProjectOrders.add(order); + this.playerIssuedOrder(); + } + this.gameState.projectOrders.remove(order); + this.ui.handleProjectOrderCanceled(order.type); + if (order.type == GameState.ResourceType.ENERGY) { + this.recalculateTacticalOverlay(); + } + } + + public void tick(final boolean var1) { + if (var1 && !ShatteredPlansClient.isPopupOpen()) { + this.processInput(); + } else { + this.ui.processInput(false); + } + + this.ui.tick(); + this.gameView.tick(this.turnEventLog != null ? this.turnEventLog.events : null); + + while (this.recentlyPlayedBuildSfxQueue != null && ShatteredPlansClient.currentTick - this.recentlyPlayedBuildSfxQueue.createdTick >= 50) { + --this.recentlyPlayedBuildSfxCounter; + this.recentlyPlayedBuildSfxQueue = this.recentlyPlayedBuildSfxQueue.next; + } + + if (this.isMultiplayer) { + if (this.turnTicksLeft > 1 && --this.turnTicksLeft == 1 && !this.readyToEndTurn && this.localPlayerIsAlive) { + this.endTurn(); + } + + if (this.turnTicksLeft % 200 == 0 && this.readyToEndTurn) { + this.sendEndTurn(); + } + } else { + --this.turnTicksLeft; + } + + if (this.isMultiplayer && this.localPlayerIsAlive && this.orderUpdateIdleTimer != -1 && (--this.orderUpdateIdleTimer == -1 || --this.orderUpdateBusyTimer < 0)) { + this.sendOutstandingOrders(C2SPacket.buffer); + } + } + + @Override + protected @NotNull Optional getAI(final @NotNull Player player) { + return Optional.ofNullable(this.ais[player.index]); + } + + @Override + public void handlePactAccepted(final @NotNull Player offerer, final @NotNull Player offeree) { + if (this.isTutorial) { + TutorialState.a984fl("signtreaty"); + } + + if (offerer == this.localPlayer) { + this.cancelOrdersToAttackPlayer(offeree); + } else if (offeree == this.localPlayer) { + this.cancelOrdersToAttackPlayer(offerer); + } + + this.recalculateTacticalOverlay(); + super.handlePactAccepted(offerer, offeree); + } + + private void cancelOrdersToAttackPlayer(final Player player) { + this.gameState.moveOrders.stream() + .filter(order -> order.quantity > 0 && order.target.owner == player) + .toList().forEach(this::cancelMoveOrder); + this.gameState.projectOrders.stream() + .filter(order -> order.type == GameState.ResourceType.ENERGY && order.target.owner == player) + .toList().forEach(this::cancelProjectOrder); + if (this.placementMode == PlacementMode.MOVE_FLEET_DEST || this.placementMode == PlacementMode.STELLAR_BOMB) { + for (final StarSystem system : this.gameState.map.systems) { + if (system.owner == player) { + this.gameView.highlightedSystems[system.index] = SystemHighlight.NONE; + } + } + } + } + + private void tutorialHandleTurnAdvance() { + if (this.isTutorial) { + for (final ProjectOrder order : this.gameState.projectOrders) { + if (order.type == GameState.ResourceType.METAL) { + TutorialState.a984fl("defensivenet"); + } else if (order.type == GameState.ResourceType.BIOMASS) { + TutorialState.a984fl("terraforming"); + } else if (order.type == GameState.ResourceType.ENERGY) { + TutorialState.a984fl("stellarbomb"); + } else if (order.type == GameState.ResourceType.EXOTICS) { + TutorialState.a984fl("tannhauser"); + } + } + + if (this.gameState.turnNumber == 0) { + if (this.gameState.gameOptions.unifiedTerritories) { + for (final Player var4 : this.gameState.players) { + var4.combinedForce.fleetsAvailableToBuild = 0; + } + } else { + for (final Player var4 : this.gameState.players) { + for (final ContiguousForce var5 : var4.contiguousForces) { + var5.fleetsAvailableToBuild = 0; + } + } + } + } + } + } + + private void updateViewStateForTurnStart() { + System.gc(); + this.gameState.victoryChecker.updateVictoryPanel(this.gameState, this.ui); + + for (final StarSystem system : this.gameState.map.systems) { + system.remainingGarrison = system.garrison; + if (system.owner == this.localPlayer) { + this.maxGarrisonsAtTurnEnd[system.index] = system.garrison; + this.minGarrisonsAtTurnEnd[system.index] = system.garrison; + } else { + this.systemsCanOwn[system.index] = false; + this.systemsWillOwn[system.index] = false; + this.maxGarrisonsAtTurnEnd[system.index] = 0; + this.minGarrisonsAtTurnEnd[system.index] = 0; + } + } + + if (this.systemOwners == null || this.systemOwners.length < this.gameState.map.systems.length) { + final int systemCount = this.gameState.map.systems.length; + this.remainingGarrisons = new int[systemCount]; + this.systemOwners = new Player[systemCount]; + this.systemForces = new ContiguousForce[systemCount]; + } + + for (final StarSystem system : this.gameState.map.systems) { + this.systemOwners[system.index] = system.owner; + this.remainingGarrisons[system.index] = system.garrison; + this.systemForces[system.index] = system.contiguousForce; + } + + this.gameView.assignSystemState(this.remainingGarrisons, this.systemForces, this.systemOwners, false); + this.gameView.setTacticalOverlay(this.systemsCanOwn, this.systemsWillOwn, this.guaranteedCollapseStages, this.possibleCollapseStages); + this.recalculateTacticalOverlay(); + if (this.isMultiplayer || this.ais[this.localPlayerIndex] == null) { + if (isAutoPlaying && !this.desynced && this.localPlayerIsAlive) { + this.ais[this.localPlayerIndex].makeDesiredPactOffers(); + this.ais[this.localPlayerIndex].planTurnOrders(); + this.recalculateTacticalOverlay(); + + this.unsentMoveOrders.addAll(this.gameState.moveOrders); + this.unsentBuildOrders.addAll(this.gameState.buildOrders); + this.unsentProjectOrders.addAll(this.gameState.projectOrders); + this.playerIssuedOrder(); + } + + this.gameView.a487(); + this.ui.updateForTurnStart(); + this.ui.setPlacementMode(PlacementMode.NONE); + this.playersWaitingOn = 0; + + for (int i = 0; i < this.gameState.playerCount; ++i) { + if (!this.gameState.isPlayerDefeated(i)) { + ++this.playersWaitingOn; + } + } + + if (this.gameState.hasEnded || this.localPlayer != null && this.gameState.isPlayerDefeated(this.localPlayerIndex)) { + this.handleVictory(); + } + } else { + try { + this.ais[this.localPlayerIndex].planTurnOrders(); + } catch (final Exception var6) { + JagexApplet.clientError(var6, "AI has errored in single player game"); + } + + this.recalculateTacticalOverlay(); + this.advanceTurnSinglePlayer(); + } + } + + private boolean isStellarBombTarget(final Player player, final StarSystem system) { + return this.gameState.projectOrders.stream().anyMatch(order -> + order.player == player && order.type == GameState.ResourceType.ENERGY && order.target == system); + } + + private void resendAllTurnOrders() { + C2SPacket.Type.ALL_TURN_ORDERS.write(C2SPacket.buffer); + C2SPacket.buffer.withLengthShort(() -> { + C2SPacket.buffer.writeByte(this.gameState.turnNumber); + this.gameState.writeTurnOrders(C2SPacket.buffer); + }); + this.unsentProjectOrders.clear(); + this.unsentBuildOrders.clear(); + this.unsentMoveOrders.clear(); + + this.orderUpdateIdleTimer = -1; + this.orderUpdateBusyTimer = -1; + if (this.readyToEndTurn) { + this.sendEndTurn(); + } + } + + private void addOrders(final @NotNull TurnOrders orders) { + orders.projectOrders.forEach(this::addOrder); + orders.buildOrders.forEach(this::addOrder); + orders.moveOrders.forEach(this::addOrder); + this.recalculateTacticalOverlay(); + this.ui.updateAvailableFleetCounters(); + } + + private void addOrder(final @NotNull BuildFleetsOrder order) { + final Force force = order.getForce(this.gameState.gameOptions); + assert this.localPlayer != null; + assert force.player == this.localPlayer; + assert force.fleetsAvailableToBuild >= order.quantity; + + final BuildFleetsOrder keptOrder = this.gameState.buildOrders.stream() + .filter(order::replaces).findFirst() + .map(Functions.tee(order::appendTo)) + .orElseGet(() -> { + this.gameState.buildOrders.add(order); + return order; + }); + + if (this.isMultiplayer) { + this.unsentBuildOrders.remove(keptOrder); + this.unsentBuildOrders.add(keptOrder); + this.playerIssuedOrder(); + } + + order.system.remainingGarrison += order.quantity; + this.remainingGarrisons[order.system.index] += order.quantity; + this.maxGarrisonsAtTurnEnd[order.system.index] += order.quantity; + this.minGarrisonsAtTurnEnd[order.system.index] += order.quantity; + force.fleetsAvailableToBuild -= order.quantity; + } + + private void addOrder(final @NotNull MoveFleetsOrder order) { + assert this.localPlayer != null; + assert order.source.owner == this.localPlayer; + assert order.source.remainingGarrison >= order.quantity; + + final MoveFleetsOrder keptOrder = order.source.outgoingOrders.stream() + .filter(order::replaces).findFirst() + .map(Functions.tee(order::appendTo)) + .orElseGet(() -> { + order.source.outgoingOrders.add(order); + order.target.incomingOrders.add(order); + this.gameState.moveOrders.add(order); + return order; + }); + + if (this.isMultiplayer) { + this.unsentMoveOrders.remove(keptOrder); + this.unsentMoveOrders.add(keptOrder); + this.playerIssuedOrder(); + } + + order.source.remainingGarrison -= order.quantity; + this.remainingGarrisons[order.source.index] -= order.quantity; + } + + private void addOrder(final @NotNull ProjectOrder order) { + this.gameState.projectOrders.stream() + .filter(order::replaces).findFirst() + .ifPresent(this.gameState.projectOrders::remove); + this.gameState.projectOrders.add(order); + if (this.isMultiplayer) { + this.unsentProjectOrders.add(order); + this.playerIssuedOrder(); + } + } + + private void addToMoveOrder(final MoveFleetsOrder order, final int quantity) { + order.source.remainingGarrison -= quantity; + this.remainingGarrisons[order.source.index] -= quantity; + order.quantity += quantity; + + if (order.quantity < 0) { + throw new RuntimeException(); + } else { + if (order.quantity == 0) { + order.source.outgoingOrders.remove(order); + order.target.incomingOrders.remove(order); + this.gameState.moveOrders.remove(order); + } + + this.recalculateTacticalOverlay(); + if (this.isMultiplayer) { + this.unsentMoveOrders.remove(order); + this.unsentMoveOrders.add(order); + this.playerIssuedOrder(); + } + } + } + + private void cancelBuildOrder(final BuildFleetsOrder order) { + order.system.remainingGarrison -= order.quantity; + this.remainingGarrisons[order.system.index] -= order.quantity; + order.getForce(this.gameState.gameOptions).fleetsAvailableToBuild += order.quantity; + order.quantity = 0; + this.unsentBuildOrders.add(order); + this.gameState.buildOrders.remove(order); + } + + private void cancelMoveOrder(final MoveFleetsOrder order) { + this.addToMoveOrder(order, -order.quantity); + } + + private void handleBuildFleets(final StarSystem targetSystem) { + final int quantity; + final int modifier = this.getModifierKey(); + if (modifier == KeyState.Code.CONTROL) { + quantity = this.selectedForce.fleetsAvailableToBuild; + } else if (modifier == KeyState.Code.ALT) { + quantity = Math.min(5, this.selectedForce.fleetsAvailableToBuild); + } else { + quantity = 1; + } + + final BuildFleetsOrder order = new BuildFleetsOrder(targetSystem, quantity); + assert order.getForce(this.gameState.gameOptions) == this.selectedForce; + this.addOrder(order); + + this.ui.updateAvailableFleetCounters(); + if (this.selectedForce.fleetsAvailableToBuild <= 0) { + if (this.localPlayer == null || this.gameState.gameOptions.unifiedTerritories) { + this.ui.setPlacementMode(PlacementMode.NONE); + } else { + this.localPlayer.contiguousForces.stream() + .filter(force -> force.fleetsAvailableToBuild > 0).findFirst() + .ifPresentOrElse(nextForce -> this.ui.activateFleetPlacement(nextForce, false), () -> { + if (this.isTutorial) { + TutorialState.a984fl("buildships"); + } + this.ui.setPlacementMode(PlacementMode.NONE); + }); + } + } else { + this.ui.setPlacementMode(PlacementMode.BUILD_FLEET); + for (final StarSystem system : this.selectedForce) { + this.gameView.highlightedSystems[system.index] = SystemHighlight.TARGET; + } + } + this.recalculateTacticalOverlay(); + } + + private void handleMoveFleets(final StarSystem source, final StarSystem target, final int quantity) { + this.addOrder(new MoveFleetsOrder(source, target, quantity)); + this.recalculateTacticalOverlay(); + } + + private void handleBuildProject(@MagicConstant(valuesFromClass = GameState.ResourceType.class) final int type, final StarSystem target) { + this.addOrder(new ProjectOrder(type, this.localPlayer, target)); + } + + private void handleBuildProject(final StarSystem source, final StarSystem target) { + this.addOrder(new ProjectOrder(this.localPlayer, source, target)); + } + + private int[] tallyPlayerFleetProduction() { + final int[] production = new int[this.gameState.playerCount]; + + for (final StarSystem system : this.gameState.map.systems) { + if (system.owner != null) { + production[system.owner.index] += system.garrison; + } + } + + for (final Player player : this.gameState.players) { + if (this.gameState.gameOptions.unifiedTerritories) { + if (player.combinedForce != null && player.combinedForce.fleetProduction > 0) { + production[player.index] += player.combinedForce.fleetProduction; + } + } else { + for (final ContiguousForce force : player.contiguousForces) { + if (force.fleetProduction > 0) { + production[player.index] += force.fleetProduction; + } + } + } + } + + return production; + } + + public void requestOrAcceptPact(final Player offeree) { + final Player offerer = this.localPlayer; // the offerer is implicitly the local player + if (!this.gameState.isPlayerDefeated(offerer.index) && !this.gameState.isPlayerDefeated(offeree.index)) { + if (offerer != offeree) { + if (!offerer.isOfferingPactTo(offeree)) { + Player.offerPact(offerer, offeree); + if (this.isMultiplayer) { + this.sendPactOrder(offeree, offerer); + if (!offerer.hasPactOfferFrom(offeree)) { + this.handlePactOffer(offerer, offeree); + } + } else if (offerer.hasPactOfferFrom(offeree)) { + Player.establishPact(offerer, offeree); + this.handlePactAccepted(offeree, offerer); + if (this.isTutorial) { + TutorialState.a984fl("signtreaty"); + } + } else { + this.handlePactOffer(offerer, offeree); + } + } + } + } + } + + private void sendPactOrder(final Player offeree, final Player offerer) { + C2SPacket.Type.ORDERS.write(C2SPacket.buffer); + C2SPacket.buffer.withLengthShort(() -> { + C2SPacket.buffer.writeByte(this.gameState.turnNumber); + C2SPacket.buffer.writeByte(C2SPacket.OrderType.PACT); + C2SPacket.buffer.writeByte(offerer.index); + C2SPacket.buffer.writeByte(offeree.index); + }); + } + + public boolean didPlayerLeave(final int index) { + return (this.leftPlayersBitmap & (1 << index)) != 0; + } + public boolean haveAllOtherPlayersLeft() { + return (1 << this.gameState.playerCount) - 1 == (this.leftPlayersBitmap | (1 << this.localPlayerIndex)); + } +} diff --git a/src/main/java/funorb/shatteredplans/client/game/CombatEngagementLog.java b/src/main/java/funorb/shatteredplans/client/game/CombatEngagementLog.java new file mode 100644 index 0000000..82a0e7b --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/CombatEngagementLog.java @@ -0,0 +1,47 @@ +package funorb.shatteredplans.client.game; + +import funorb.shatteredplans.game.MoveFleetsOrder; +import funorb.shatteredplans.game.Player; +import funorb.shatteredplans.map.StarSystem; + +import java.util.ArrayList; +import java.util.List; + +public final class CombatEngagementLog implements TurnEventLog.Event { + public final StarSystem system; + public final Player[] players; + public final Player ownerAtCombatStart; + public final int[] fleetsAtCombatStart; + public final List events = new ArrayList<>(); + public int totalKills; + public int[] playerKills; + public Player victor; + public int fleetsAtCombatEnd; + + public CombatEngagementLog(final StarSystem system, final Player[] players, final int[] fleetsAtCombatStart) { + this.system = system; + this.players = players; + this.fleetsAtCombatStart = fleetsAtCombatStart.clone(); + this.ownerAtCombatStart = this.system.owner; + this.totalKills = 0; + } + + public void setPlayerKills(final int[] playerKills) { + this.playerKills = playerKills; + } + + public void a115(final int var2, final int var1, final int var3) { + this.totalKills += var1; + this.events.add(new CombatLogEvent(this.ownerAtCombatStart, var2, var1, var3)); + } + + public void a326(final int fleetsAtStart, final int fleetsKilled) { + this.totalKills += fleetsKilled; + this.events.add(new CombatLogEvent(this.ownerAtCombatStart, fleetsAtStart, fleetsKilled, 0)); + } + + public void a631(final MoveFleetsOrder order, final int destroyed, final int retreated) { + this.events.add(new CombatLogEvent(order, destroyed, retreated)); + this.totalKills += destroyed; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/game/CombatExplosion.java b/src/main/java/funorb/shatteredplans/client/game/CombatExplosion.java new file mode 100644 index 0000000..c84e02d --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/CombatExplosion.java @@ -0,0 +1,25 @@ +package funorb.shatteredplans.client.game; + +import funorb.audio.PlayingSound; +import funorb.shatteredplans.client.ShatteredPlansClient; +import funorb.shatteredplans.client.Sounds; +import funorb.shatteredplans.map.StarSystem; + +public final class CombatExplosion { + public static final int LIFETIME = 130; + public final int x; + public final int y; + public final StarSystem system; + public final PlayingSound sound; + public int ticksAlive = 0; + + public CombatExplosion(final StarSystem system) { + this.system = system; + this.sound = Sounds.play(Sounds.SFX_EXPLOSION, 0); + + final double angle = Math.random() * Math.PI * 2.0D; + final int fac = 0x4000 + ShatteredPlansClient.randomIntBounded(0x4000); + this.x = (int) (Math.sin(angle) * (double) fac); + this.y = (int) (Math.cos(angle) * (double) fac); + } +} diff --git a/src/main/java/funorb/shatteredplans/client/game/CombatLogEvent.java b/src/main/java/funorb/shatteredplans/client/game/CombatLogEvent.java new file mode 100644 index 0000000..e7765d0 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/CombatLogEvent.java @@ -0,0 +1,29 @@ +package funorb.shatteredplans.client.game; + +import funorb.shatteredplans.game.MoveFleetsOrder; +import funorb.shatteredplans.game.Player; +import funorb.shatteredplans.map.StarSystem; + +public final class CombatLogEvent { + public final Player player; + public final StarSystem source; + public final int fleetsAtStart; + public final int fleetsDestroyed; + public final int fleetsRetreated; + + public CombatLogEvent(final MoveFleetsOrder order, final int fleetsDestroyed, final int fleetsRetreated) { + this.player = order.player; + this.source = order.source; + this.fleetsAtStart = order.quantity; + this.fleetsDestroyed = fleetsDestroyed; + this.fleetsRetreated = fleetsRetreated; + } + + public CombatLogEvent(final Player player, final int fleetsAtStart, final int fleetsDestroyed, final int fleetsRetreated) { + this.player = player; + this.source = null; + this.fleetsAtStart = fleetsAtStart; + this.fleetsRetreated = fleetsRetreated; + this.fleetsDestroyed = fleetsDestroyed; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/game/FleetRetreatEvent.java b/src/main/java/funorb/shatteredplans/client/game/FleetRetreatEvent.java new file mode 100644 index 0000000..81b2e26 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/FleetRetreatEvent.java @@ -0,0 +1,20 @@ +package funorb.shatteredplans.client.game; + +import funorb.shatteredplans.map.StarSystem; + +public final class FleetRetreatEvent implements TurnEventLog.Event { + public final StarSystem source; + public final StarSystem[] targets; + public int[] quantities; + + public FleetRetreatEvent(final StarSystem source) { + this.source = source; + this.targets = null; + } + + public FleetRetreatEvent(final StarSystem source, final StarSystem[] targets, final int[] quantities) { + this.source = source; + this.targets = targets; + this.quantities = quantities; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/game/GameView.java b/src/main/java/funorb/shatteredplans/client/game/GameView.java new file mode 100644 index 0000000..3b73a8e --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/GameView.java @@ -0,0 +1,3701 @@ +package funorb.shatteredplans.client.game; + +import funorb.Strings; +import funorb.graphics.ArgbSprite; +import funorb.graphics.Drawing; +import funorb.graphics.Point; +import funorb.graphics.Rect; +import funorb.graphics.Sprite; +import funorb.graphics.vector.VectorDrawing; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.CombatEngagementAnimationState; +import funorb.shatteredplans.client.GameUI; +import funorb.shatteredplans.client.Menu; +import funorb.shatteredplans.client.ShatteredPlansClient; +import funorb.shatteredplans.client.Sounds; +import funorb.shatteredplans.game.GameState; +import funorb.shatteredplans.game.GameState.ResourceType; +import funorb.shatteredplans.game.MoveFleetsOrder; +import funorb.shatteredplans.game.Player; +import funorb.shatteredplans.game.ProjectOrder; +import funorb.shatteredplans.map.Map; +import funorb.shatteredplans.map.StarSystem; +import funorb.shatteredplans.map.TannhauserLink; +import funorb.util.ArrayUtil; +import funorb.util.MathUtil; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +public final class GameView extends AbstractGameView { + public static final int[] RESOURCE_COLORS = new int[]{0x7fbfff, 0x7fdf2f, 0xff7f00, 0xff00ff}; + public static final double COS_THIRTY_DEGREES = Math.cos(0.5235987755982988D); // sqrt(3)/2 + private static final int[] _rj = new int[]{-65536, -65536, -65536, 0, -65536}; + private static final int TICKS_PER_ANIMATION_PHASE = 200; + public static Sprite[] DEFNET_ANIM_MID; + public static Sprite[] DEFNET_ANIM_LARGE; + private static int _ch; + private static int _ce; + private static int _ca; + public static int uiPulseCounter; + public static Sprite ARROW_SHIP; + public static Sprite ARROW_SHIP_DAMAGED; + private static int[] _enb; + public static Sprite COMBAT_HEX_WHITE; + public static Sprite SHIELD; + public static Sprite DEFENSE_GRID; + public static Sprite CHEVRON; + public static Sprite WARNING; + public static Sprite HAMMER; + public static Sprite FLEETS_ARROW_SHIP; + public static Sprite[] FLEET_BUTTONS; + public static Sprite[] RES_SIDES; + public static Sprite[] RES_LOWS; + public static ArgbSprite _cos; + public static Sprite[] DEFNET_ANIM_SMALL; + public static Sprite[] SYSTEM_ICONS; + private static int[] _aib; + private static int _cd; + private static int _cc; + private static int _cb2; + private static int _cg; + private static int[] _cf; + public final int[] _nb = new int[]{-1, -1}; + private final boolean isTutorial; + private final int[] _tb = new int[]{-1, -1}; + private final ArgbSprite[][] resourceLightSprites; + private final int[] _ub = new int[]{-1, -1}; + public boolean _Bb; + public boolean _Gb; + public boolean _Ab; + public MoveFleetsOrder _rb; + private Sprite[] _Mb; + private ArgbSprite _K; + private double _wb; + private ArgbSprite _ob; + private Sprite[] _Kb; + private int _yb = 0; + private ArgbSprite _Cb; + private double _Nb = -1.0; + private int _Hb; + private double zoomFactor; + private MoveFleetsOrder _Db; + private int[][] _Qb; + private ArgbSprite _Ib; + private Sprite[] _xb; + private ArgbSprite _Ob; + + public GameView(final Map var1, final Player[] var2, final Player localPlayer, final boolean isTutorial) { + super(localPlayer); + this._ib = var2; + this.map = var1; + this.isTutorial = isTutorial; + this._cb = new int[this._ib.length][]; + this.j150(); + this.mapScrollPosnX = (float) (this.map.drawingWidth / 2); + this.mapScrollPosnY = (float) (this.map.drawingHeight / 2); + this.unitScalingFactor = 300.0F; + this.maxUnitScalingFactor = (float) (this.map.drawingWidth * 300 / 450); + + for (int i = 0; i < GameState.NUM_RESOURCES; ++i) { + this.projectHighlightColors[i] = new int[256]; + } + for (int i = 0; i < 0x100; ++i) { + this.projectHighlightColors[ResourceType.METAL ][i] = ((i & 0xfe) << 7) | i; + this.projectHighlightColors[ResourceType.BIOMASS][i] = i << 8; + this.projectHighlightColors[ResourceType.ENERGY ][i] = i << 8 | i << 16; + this.projectHighlightColors[ResourceType.EXOTICS][i] = i << 16 | i; + } + + this.highlightedSystems = new SystemHighlight[this.map.systems.length]; + Arrays.fill(this.highlightedSystems, SystemHighlight.NONE); + this.fleetMovements = new ArrayList<>(); + this.combatEngagements = new ArrayList<>(); + this.buildEvents = new ArrayList<>(); + this.combatRetreats = new ArrayList<>(); + this.collapseRetreats = new ArrayList<>(); + this.combatExplosions = new ArrayList<>(); + this.retreatTargets = new boolean[this.map.systems.length]; + this.resourceLightSprites = new ArgbSprite[4][6]; + + for (int i = 0; i < 6; ++i) { + final ArgbSprite side = (ArgbSprite) RES_SIDES[i]; + final ArgbSprite low = (ArgbSprite) RES_LOWS[i]; + this.resourceLightSprites[0][i] = side.copy(); + this.resourceLightSprites[1][i] = low.copy(); + this.resourceLightSprites[2][i] = low.copy(); + this.resourceLightSprites[2][i].flipHorizontal(); + this.resourceLightSprites[3][i] = side.copy(); + this.resourceLightSprites[3][i].flipHorizontal(); + } + + for (int i = 0; i < GameState.NUM_RESOURCES; ++i) { + final int var16 = RESOURCE_COLORS[i]; + final int r = (var16 >> 16) & 0xff; + final int g = (var16 >> 8) & 0xff; + final int b = var16 & 0xff; + + for (int j = 0; j < 6; ++j) { + for (int k = 0; k < this.resourceLightSprites[i][j].pixels.length; ++k) { + final int var13 = (this.resourceLightSprites[i][j].pixels[k] & 0xff0000) >> 16; + final int var14 = (this.resourceLightSprites[i][j].pixels[k] & Drawing.GREEN) >> 8; + final int var15 = 255 & this.resourceLightSprites[i][j].pixels[k]; + if (var14 == var13 && var13 == var15) { + if (var13 <= 128) { + this.resourceLightSprites[i][j].pixels[k] = (0xff000000 & this.resourceLightSprites[i][j].pixels[k]) + (b * var15 >> 7) + (g * var14 >> 7 << 8) + (r * var13 >> 7 << 16); + } else { + this.resourceLightSprites[i][j].pixels[k] = (0xff000000 & this.resourceLightSprites[i][j].pixels[k]) + (b * (256 - var15) - (32640 - 255 * var15) >> 7) + ((-var14 + 256) * g - 32640 + var14 * 255 >> 7 << 8) + (255 * (var13 - 128) + r * (-var13 + 256) >> 7 << 16); + } + } + } + } + } + } + + private static void drawLine(int x1, int y1, int x2, int y2, final int color) { + y1 >>= 4; + x1 >>= 4; + x2 >>= 4; + y2 >>= 4; + int tmp; + if (x1 > x2) { + tmp = x1; + x1 = x2; + x2 = tmp; + + tmp = y1; + y1 = y2; + y2 = tmp; + } + + if (x2 >= Drawing.left && x1 <= Drawing.right) { + if (y1 > y2) { + tmp = x1; + x1 = x2; + x2 = tmp; + + tmp = y1; + y1 = y2; + y2 = tmp; + } + + if (y2 >= Drawing.top && y1 <= Drawing.bottom) { + Drawing.line(x1, y1, x2, y2, color); + } + } + } + + public static void a070eo(final boolean var0, final int var1, final int var2, final int var3, final int var4, final int var5) { + final double var6 = Math.sqrt(MathUtil.euclideanDistanceSquared(var4 - var5, var2 - var1)); + final double var8 = (double) (var4 - var5) / var6; + final double var10 = (double) (-var1 + var2) / var6; + int var12; + int var13; + if (var4 <= var5) { + var13 = var5; + var12 = var4; + } else { + var12 = var5; + var13 = var4; + } + + int var14; + int var15; + if (var2 > var1) { + var15 = var2; + var14 = var1; + } else { + var15 = var1; + var14 = var2; + } + + if (var8 > 0.0D) { + var14 -= 4; + var15 = (int) ((double) var15 + 4.0D + var8 * var6 / 10.0D); + } else { + var15 += 4; + var14 = (int) ((double) var14 + (var6 * var8 / 10.0D - 5.0D)); + } + + if (var10 > 0.0D) { + var13 += 4; + var12 = (int) ((double) var12 - (5.0D + var6 * var10 / 10.0D)); + } else { + var13 = (int) ((double) var13 - (-5.0 + var6 * var10 / 10.0D)); + var12 -= 4; + } + + if (var12 < 0) { + var12 = 0; + } + + if (var14 < 0) { + var14 = 0; + } + + if (var13 > 639) { + var13 = 639; + } + + if (var15 > 479) { + var15 = 479; + } + + final double var36 = 1.0D / var6; + final double var38 = var6 / 2.0D; + final double var40 = 1.0D / var38; + final double var42 = var10 != 0.0D ? 1.0D / var10 : 0.0D; + final double var44 = var6 / 10.0D; + double var46 = var1 - var2; + double var48 = -var4 + var5; + final double var50 = Math.sqrt(var46 * var46 + var48 * var48); + var48 /= var50; + var46 /= var50; + double var52 = (var44 + 4.0D) / Math.cos(Math.atan(var8 / var10)); + if (var52 < 0.0D) { + var52 = -var52; + } + + for (int var55 = 0; var55 < var15 + (1 - var14); ++var55) { + final int var33 = var14 + (var55 - var1); + final double var25 = (double) var33 * var42; + final double var27 = (double) var5 + var8 * var25; + int var34; + int var35; + if (var10 >= 0.0D) { + if (var10 == 0.0D) { + var35 = 1 + var13 - var12; + var34 = 0; + } else { + var35 = (int) ((double) (-var12) + 8.0D + var27); + var34 = -var12 + (int) (var27 - var52); + if (var34 < 0) { + var34 = 0; + } + } + } else { + var35 = (int) (var27 + var52) + 1 - var12; + var34 = (int) ((double) (-var12) + (var27 - 8.0D)); + if (-var12 + var13 + 1 < var35) { + var35 = 1 + (var13 - var12); + } + } + + for (int var56 = var34; var35 > var56; ++var56) { + final double var31 = -var27 + (double) (var56 + var12); + final double var19 = -(var31 * var48) + var25; + if (var19 >= 0.0D && var19 <= var6 * (double) var3 / 200.0D) { + final double var17; + if (var6 / 4.0D <= var19) { + var17 = 4.0D; + } else { + var17 = 1.0D + var36 * 4.0D * var19 * 3.0D; + } + + final double var23; + if (var10 == 0.0D) { + var23 = var8 * (double) var33; + } else { + var23 = var31 * var46; + } + + final double var21 = var44 - (-var38 + var19) * (var19 - var38) * var40 * 0.2D; + double var29 = -var21 + var23; + if (var29 < 0.0D) { + var29 = -var29; + } + + if (var29 <= var17) { + if (var19 > var6) { + var29 = Math.sqrt((var12 + var56 - var4) * (-var4 + var12 + var56) + (var14 - (-var55 + var2)) * (-var2 + var55 + var14)); + if (var29 > var17) { + continue; + } + } + + final int var16 = (int) (160.0D * (var17 - var29) / var17); + if (var0) { + Drawing.setPixel(var56, var55, var16 << 24 | Drawing.WHITE); + } else { + Drawing.addPixel(var12 + var56, var55 + var14, Drawing.WHITE, var16); + } + } + } + } + } + + } + + private static void a669tue(int var0, int var1, int var2, final int var3, int var4) { + int var5 = 0; + int var6 = 0; + final int var7 = Drawing.left << 4; + final int var8 = Drawing.right << 4; + if (var2 > var1) { + final int var9 = var2; + var2 = var1; + var1 = var9; + final int i = var0; + var0 = var4; + var4 = i; + } + + if (var1 >= var7 && var2 <= var8) { + final long var14 = -var2 + var1; + if (var1 > var8) { + var6 = (int) ((long) (var1 - var8) * 65536L / var14); + } + + final long var11 = var4 - var0; + if (var2 < var7) { + var5 = (int) ((long) (-var2 + var7) * 65536L / var14); + } + + final int i = Drawing.bottom << 4; + var4 -= (int) ((long) var6 * var11 >> 16); + var1 -= (int) (var14 * (long) var6 >> 16); + var0 += (int) (var11 * (long) var5 >> 16); + final int i1 = Drawing.top << 4; + var2 += (int) (var14 * (long) var5 >> 16); + if (var4 < var0) { + final int var13 = var2; + var2 = var1; + var1 = var13; + final int var01 = var0; + var0 = var4; + var4 = var01; + } + + if (var4 >= i1 && var0 <= i) { + int i2 = 0; + int i3 = 0; + final long l = var4 - var0; + if (i < var4) { + i2 = (int) ((long) (-i + var4) * 65536L / (long) (var4 - var0)); + } + + if (var0 < i1) { + i3 = (int) (65536L * (long) (-var0 + i1) / (long) (var4 - var0)); + } + + final long i4 = -var2 + var1; + var4 -= (int) (l * (long) i2 >> 16); + var1 -= (int) (i4 * (long) i2 >> 16); + var2 += (int) ((long) i3 * i4 >> 16); + var0 += (int) (l * (long) i3 >> 16); + a022ar(var1, var2, var4, var0, var3); + } + } + } + + private static void a022ar(final int var0, final int var1, final int var2, final int var3, final int var4) { + if ((Math.abs(var1) | Math.abs(var3) | Math.abs(var0) | Math.abs(var2)) >>> 19 == 0) { + if (Math.abs(var0 - var1) < Math.abs(var2 - var3)) { + a669in(var4, var3, var2, var1, var0); + } else { + a802tue(var2, var1, var0, var4, var3); + } + } + } + + private static void a802tue(int var0, int var1, int var2, final int var3, int var4) { + int var5; + if (var2 < var1) { + var5 = var2; + var2 = var1; + var1 = var5; + var5 = var0; + var0 = var4; + var4 = var5; + } + + var5 = -var1 + var2; + final int var6 = -var4 + var0; + int var7; + int var8; + int var9; + int var10; + int var11; + int var12; + int var13; + if (var5 == 0) { + if (var6 < 16) { + var7 = var1 >> 4; + var8 = var4 >> 4; + var10 = (16 - (15 & var1)) * var6; + if (Drawing.left <= var7 && Drawing.right > var7 && var8 >= Drawing.top && var8 < Drawing.bottom) { + var10 = (int) (256.0D * Math.pow((double) var10 / 256.0D, 0.55D)); + var11 = var3 & '\uff00'; + var9 = var3 & 16711935; + var11 *= var10; + var11 &= 16711680; + var9 *= var10; + var9 &= -16711936; + var12 = var7 + var8 * ShatteredPlansClient.SCREEN_WIDTH; + var13 = Drawing.screenBuffer[var12]; + var9 += -16711936 & (var13 & 16711935) * (256 - var10); + var11 += 16711680 & (-var10 + 256) * ('\uff00' & var13); + Drawing.screenBuffer[var12] = (var11 | var9) >>> 8; + } + + var7 = 1 + (var1 >> 4); + var8 = var4 >> 4; + var10 = (15 & var1) * var6; + if (Drawing.left <= var7 && Drawing.right > var7 && Drawing.top <= var8 && Drawing.bottom > var8) { + var10 = (int) (Math.pow((double) var10 / 256.0D, 0.55D) * 256.0D); + var11 = '\uff00' & var3; + var9 = var3 & 16711935; + var11 *= var10; + var11 &= 16711680; + var9 *= var10; + var9 &= -16711936; + var12 = var8 * ShatteredPlansClient.SCREEN_WIDTH + var7; + var13 = Drawing.screenBuffer[var12]; + var11 += 16711680 & (-var10 + 256) * (var13 & '\uff00'); + var9 += -16711936 & (16711935 & var13) * (-var10 + 256); + Drawing.screenBuffer[var12] = (var11 | var9) >>> 8; + } + } else { + var7 = var1 >> 4; + var8 = var4 >> 4; + var10 = (-(var1 & 15) + 16) * (16 - (var4 & 15)); + if (Drawing.left <= var7 && var7 < Drawing.right && var8 >= Drawing.top && var8 < Drawing.bottom) { + var10 = (int) (256.0D * Math.pow((double) var10 / 256.0D, 0.55D)); + var11 = '\uff00' & var3; + var9 = var3 & 16711935; + var11 *= var10; + var9 *= var10; + var11 &= 16711680; + var9 &= -16711936; + var12 = var8 * ShatteredPlansClient.SCREEN_WIDTH + var7; + var13 = Drawing.screenBuffer[var12]; + var11 += (-var10 + 256) * ('\uff00' & var13) & 16711680; + var9 += -16711936 & (var13 & 16711935) * (256 - var10); + Drawing.screenBuffer[var12] = (var9 | var11) >>> 8; + } + + var7 = var1 >> 4; + var8 = var0 >> 4; + var10 = (15 & var0) * (16 - (15 & var1)); + if (Drawing.left <= var7 && Drawing.right > var7 && Drawing.top <= var8 && Drawing.bottom > var8) { + var10 = (int) (Math.pow((double) var10 / 256.0D, 0.55D) * 256.0D); + var11 = var3 & '\uff00'; + var11 *= var10; + var9 = var3 & 16711935; + var9 *= var10; + var11 &= 16711680; + var9 &= -16711936; + var12 = var8 * ShatteredPlansClient.SCREEN_WIDTH + var7; + var13 = Drawing.screenBuffer[var12]; + var11 += (-var10 + 256) * (var13 & '\uff00') & 16711680; + var9 += -16711936 & (-var10 + 256) * (var13 & 16711935); + Drawing.screenBuffer[var12] = (var9 | var11) >>> 8; + } + + Drawing.verticalLine(var1 >> 4, 1 + (var4 >> 4), (var6 >> 4) - 2, var3, 256 - 16 * (15 & var1)); + var7 = (var1 >> 4) + 1; + var8 = var4 >> 4; + var10 = (15 & var1) * (16 - (var4 & 15)); + if (var7 >= Drawing.left && Drawing.right > var7 && var8 >= Drawing.top && var8 < Drawing.bottom) { + var10 = (int) (Math.pow((double) var10 / 256.0D, 0.55D) * 256.0D); + var11 = var3 & '\uff00'; + var9 = var3 & 16711935; + var11 *= var10; + var9 *= var10; + var11 &= 16711680; + var9 &= -16711936; + var12 = var8 * ShatteredPlansClient.SCREEN_WIDTH + var7; + var13 = Drawing.screenBuffer[var12]; + var11 += ('\uff00' & var13) * (256 - var10) & 16711680; + var9 += (16711935 & var13) * (-var10 + 256) & -16711936; + Drawing.screenBuffer[var12] = (var9 | var11) >>> 8; + } + + var7 = (var1 >> 4) + 1; + var8 = var0 >> 4; + var10 = (15 & var1) * (15 & var0); + if (Drawing.left <= var7 && var7 < Drawing.right && Drawing.top <= var8 && Drawing.bottom > var8) { + var10 = (int) (Math.pow((double) var10 / 256.0D, 0.55D) * 256.0D); + var11 = var3 & '\uff00'; + var11 *= var10; + var9 = var3 & 16711935; + var11 &= 16711680; + var9 *= var10; + var9 &= -16711936; + var12 = var8 * ShatteredPlansClient.SCREEN_WIDTH + var7; + var13 = Drawing.screenBuffer[var12]; + var9 += (var13 & 16711935) * (-var10 + 256) & -16711936; + var11 += 16711680 & (var13 & '\uff00') * (256 - var10); + Drawing.screenBuffer[var12] = (var11 | var9) >>> 8; + } + + Drawing.verticalLine(1 + (var1 >> 4), 1 + (var4 >> 4), (var6 >> 4) - 2, var3, (15 & var1) * 16); + } + + } else { + var7 = (var6 << 12) / var5; + var8 = var1 + 7 >> 4; + var9 = var7 * (-var1 + (var8 << 4)) + (var4 << 12); + var10 = 16 - (15 & var1 + 7); + var11 = var8; + var12 = var9 >> 16; + int var17 = (16 - ((var9 & '\uf326') >> 12)) * var10; + int var16; + int var18; + int var19; + int var20; + if (Drawing.left <= var8 && var8 < Drawing.right && Drawing.top <= var12 && var12 < Drawing.bottom) { + var17 = (int) (Math.pow((double) var17 / 256.0D, 0.55D) * 256.0D); + var18 = var3 & '\uff00'; + var16 = var3 & 16711935; + var18 *= var17; + var16 *= var17; + var18 &= 16711680; + var16 &= -16711936; + var19 = var8 + ShatteredPlansClient.SCREEN_WIDTH * var12; + var20 = Drawing.screenBuffer[var19]; + var18 += (var20 & '\uff00') * (256 - var17) & 16711680; + var16 += -16711936 & (var20 & 16711935) * (-var17 + 256); + Drawing.screenBuffer[var19] = (var18 | var16) >>> 8; + } + + var13 = var7 + var9; + final int var15 = 1 + var12; + int i = (15 & var9 >> 12) * var10; + if (Drawing.left <= var8 && Drawing.right > var8 && Drawing.top <= var15 && Drawing.bottom > var15) { + i = (int) (Math.pow((double) i / 256.0D, 0.55D) * 256.0D); + var18 = var3 & '\uff00'; + var18 *= i; + var16 = var3 & 16711935; + var16 *= i; + var18 &= 16711680; + var16 &= -16711936; + var19 = var8 + var15 * ShatteredPlansClient.SCREEN_WIDTH; + var20 = Drawing.screenBuffer[var19]; + var18 += (var20 & '\uff00') * (-i + 256) & 16711680; + var16 += (-i + 256) * (16711935 & var20) & -16711936; + Drawing.screenBuffer[var19] = (var18 | var16) >>> 8; + } + + var8 = var2 + 7 >> 4; + var9 = var7 * (-var2 + (var8 << 4)) + (var0 << 12); + var10 = 16 - (var2 + 7 & 15); + final int var14 = var8; + final int i1 = var9 >> 16; + var19 = (16 - (var9 >> 12 & 15)) * var10; + int var21; + int var22; + if (Drawing.left <= var8 && Drawing.right > var8 && i1 >= Drawing.top && Drawing.bottom > i1) { + var19 = (int) (Math.pow((double) var19 / 256.0D, 0.55D) * 256.0D); + var20 = '\uff00' & var3; + var20 *= var19; + var18 = var3 & 16711935; + var18 *= var19; + var20 &= 16711680; + var18 &= -16711936; + var21 = i1 * ShatteredPlansClient.SCREEN_WIDTH + var8; + var22 = Drawing.screenBuffer[var21]; + var20 += ('\uff00' & var22) * (-var19 + 256) & 16711680; + var18 += (256 - var19) * (var22 & 16711935) & -16711936; + Drawing.screenBuffer[var21] = (var18 | var20) >>> 8; + } + + int i2 = 1 + i1; + var19 = var10 * (var9 >> 12 & 15); + if (var8 >= Drawing.left && Drawing.right > var8 && Drawing.top <= i2 && i2 < Drawing.bottom) { + var19 = (int) (256.0D * Math.pow((double) var19 / 256.0D, 0.55D)); + var20 = '\uff00' & var3; + var20 *= var19; + var18 = var3 & 16711935; + var18 *= var19; + var20 &= 16711680; + var18 &= -16711936; + var21 = ShatteredPlansClient.SCREEN_WIDTH * i2 + var8; + var22 = Drawing.screenBuffer[var21]; + var18 += (var22 & 16711935) * (-var19 + 256) & -16711936; + var20 += ('\uff00' & var22) * (256 - var19) & 16711680; + Drawing.screenBuffer[var21] = (var20 | var18) >>> 8; + } + + var7 <<= 4; + ++var11; + + while (var14 > var11) { + i2 = var13 >> 16; + var19 = 256 - (var13 >> 8 & 255); + if (Drawing.left <= var11 && var11 < Drawing.right && i2 >= Drawing.top && Drawing.bottom > i2) { + var19 = (int) (Math.pow((double) var19 / 256.0D, 0.55D) * 256.0D); + var20 = var3 & '\uff00'; + var18 = var3 & 16711935; + var20 *= var19; + var20 &= 16711680; + var18 *= var19; + var18 &= -16711936; + var21 = var11 + ShatteredPlansClient.SCREEN_WIDTH * i2; + var22 = Drawing.screenBuffer[var21]; + var18 += -16711936 & (-var19 + 256) * (16711935 & var22); + var20 += 16711680 & (256 - var19) * (var22 & '\uff00'); + Drawing.screenBuffer[var21] = (var20 | var18) >>> 8; + } + + i2 = (var13 >> 16) + 1; + var19 = (var13 & '\uffd1') >> 8; + if (var11 >= Drawing.left && Drawing.right > var11 && i2 >= Drawing.top && Drawing.bottom > i2) { + var19 = (int) (256.0D * Math.pow((double) var19 / 256.0D, 0.55D)); + var20 = '\uff00' & var3; + var20 *= var19; + var18 = var3 & 16711935; + var20 &= 16711680; + var18 *= var19; + var18 &= -16711936; + var21 = i2 * ShatteredPlansClient.SCREEN_WIDTH + var11; + var22 = Drawing.screenBuffer[var21]; + var20 += (256 - var19) * ('\uff00' & var22) & 16711680; + var18 += -16711936 & (16711935 & var22) * (256 - var19); + Drawing.screenBuffer[var21] = (var18 | var20) >>> 8; + } + + var13 += var7; + ++var11; + } + + } + } + + private static int[] a385qp(final int[] var1) { + final int var2 = var1.length; + if (_aib == null || _aib.length < var2 * 2) { + _aib = new int[2 * var2]; + _enb = new int[var2 * 2]; + } + + int _bpr = 0; + int var5 = var1[var2 - 2]; + int var6 = var1[var2 - 1]; + + int var3; + int var4; + for (int var7 = 0; var7 < var2; var7 += 2) { + var3 = var5; + var4 = var6; + var5 = var1[var7]; + var6 = var1[var7 + 1]; + if (Drawing.left > var5) { + if (Drawing.left <= var3) { + _aib[_bpr++] = Drawing.left; + _aib[_bpr++] = var4 + (var6 - var4) * (Drawing.left - var3) / (-var3 + var5); + } + } else { + if (Drawing.left > var3) { + _aib[_bpr++] = Drawing.left; + _aib[_bpr++] = var6 + (-var5 + Drawing.left) * (-var6 + var4) / (var3 - var5); + } + + _aib[_bpr++] = var5; + _aib[_bpr++] = var6; + } + } + + if (_bpr == 0) { + return null; + } else { + final int[] var13 = _enb; + _enb = _aib; + _aib = var13; + int var100 = 0; + int i = _enb[_bpr - 2]; + int i1 = _enb[_bpr - 1]; + + int var8; + for (var8 = 0; _bpr > var8; var8 += 2) { + var3 = i; + var4 = i1; + i1 = _enb[1 + var8]; + i = _enb[var8]; + if (Drawing.right <= i) { + if (var3 < Drawing.right) { + _aib[var100++] = Drawing.right; + _aib[var100++] = var4 + (-var4 + i1) * (Drawing.right - var3) / (-var3 + i); + } + } else { + if (var3 >= Drawing.right) { + _aib[var100++] = Drawing.right; + _aib[var100++] = (var4 - i1) * (-i + Drawing.right) / (var3 - i) + i1; + } + + _aib[var100++] = i; + _aib[var100++] = i1; + } + } + + if (var100 == 0) { + return null; + } else { + final int[] b = _enb; + _enb = _aib; + _aib = b; + int var101 = 0; + int i2 = _enb[var100 - 2]; + int i3 = _enb[var100 - 1]; + + for (var8 = 0; var100 > var8; var8 += 2) { + var4 = i3; + var3 = i2; + i3 = _enb[var8 + 1]; + i2 = _enb[var8]; + if (i3 < Drawing.top) { + if (var4 >= Drawing.top) { + _aib[var101++] = var3 + (Drawing.top - var4) * (-var3 + i2) / (-var4 + i3); + _aib[var101++] = Drawing.top; + } + } else { + if (var4 < Drawing.top) { + _aib[var101++] = i2 + (-i2 + var3) * (-i3 + Drawing.top) / (var4 - i3); + _aib[var101++] = Drawing.top; + } + + _aib[var101++] = i2; + _aib[var101++] = i3; + } + } + + if (var101 == 0) { + return null; + } else { + final int[] ints = _enb; + _enb = _aib; + _aib = ints; + int var102 = 0; + int i4 = _enb[var101 - 1]; + int i5 = _enb[var101 - 2]; + + for (var8 = 0; var8 < var101; var8 += 2) { + var3 = i5; + var4 = i4; + i5 = _enb[var8]; + i4 = _enb[1 + var8]; + if (i4 < Drawing.bottom) { + if (Drawing.bottom <= var4) { + _aib[var102++] = (-i5 + var3) * (Drawing.bottom - i4) / (var4 - i4) + i5; + _aib[var102++] = Drawing.bottom; + } + + _aib[var102++] = i5; + _aib[var102++] = i4; + } else if (var4 < Drawing.bottom) { + _aib[var102++] = (Drawing.bottom - var4) * (i5 - var3) / (i4 - var4) + var3; + _aib[var102++] = Drawing.bottom; + } + } + + if (var102 == 0) { + return null; + } else { + final int[] var14 = new int[var102]; + System.arraycopy(_aib, 0, var14, 0, var102); + return var14; + } + } + } + } + } + + private static void drawSystemHex(final int[] points, final int color, final int alpha) { + c797c(); + a397c(points, points.length); + d797c(); + while (a801c()) { + Drawing.horizontalLine(_ce, _ch, -_ce + _ca, color, alpha); + } + } + + private static void a669in(final int var0, int var1, int var3, int var4, int var5) { + int var6; + if (var1 > var3) { + var6 = var3; + var3 = var1; + var1 = var6; + var6 = var5; + var5 = var4; + var4 = var6; + } + + var6 = -var4 + var5; + final int var7 = -var1 + var3; + int var8; + int var9; + int var10; + int var11; + int var12; + int var13; + int var14; + if (var7 == 0) { + if (var6 < 16) { + var8 = var4 >> 4; + var9 = var1 >> 4; + var11 = (16 - (var1 & 15)) * var6; + if (var8 >= Drawing.left && var8 < Drawing.right && Drawing.top <= var9 && Drawing.bottom > var9) { + var11 = (int) (Math.pow((double) var11 / 256.0D, 0.55D) * 256.0D); + var12 = '\uff00' & var0; + var10 = var0 & 16711935; + var12 *= var11; + var10 *= var11; + var12 &= 16711680; + var10 &= -16711936; + var13 = ShatteredPlansClient.SCREEN_WIDTH * var9 + var8; + var14 = Drawing.screenBuffer[var13]; + var12 += 16711680 & ('\uff00' & var14) * (256 - var11); + var10 += (16711935 & var14) * (-var11 + 256) & -16711936; + Drawing.screenBuffer[var13] = (var12 | var10) >>> 8; + } + + var8 = var4 >> 4; + var9 = (var1 >> 4) + 1; + var11 = var6 * (var1 & 15); + if (var8 >= Drawing.left && var8 < Drawing.right && var9 >= Drawing.top && var9 < Drawing.bottom) { + var11 = (int) (Math.pow((double) var11 / 256.0D, 0.55D) * 256.0D); + var12 = '\uff00' & var0; + var10 = var0 & 16711935; + var12 *= var11; + var12 &= 16711680; + var10 *= var11; + var10 &= -16711936; + var13 = var8 + ShatteredPlansClient.SCREEN_WIDTH * var9; + var14 = Drawing.screenBuffer[var13]; + var12 += (var14 & '\uff00') * (-var11 + 256) & 16711680; + var10 += (16711935 & var14) * (-var11 + 256) & -16711936; + Drawing.screenBuffer[var13] = (var10 | var12) >>> 8; + } + } else { + var8 = var4 >> 4; + var9 = var1 >> 4; + var11 = (16 - (15 & var4)) * (16 - (var1 & 15)); + if (var8 >= Drawing.left && var8 < Drawing.right && var9 >= Drawing.top && var9 < Drawing.bottom) { + var11 = (int) (256.0D * Math.pow((double) var11 / 256.0D, 0.55D)); + var12 = var0 & '\uff00'; + var12 *= var11; + var10 = var0 & 16711935; + var12 &= 16711680; + var10 *= var11; + var10 &= -16711936; + var13 = ShatteredPlansClient.SCREEN_WIDTH * var9 + var8; + var14 = Drawing.screenBuffer[var13]; + var10 += -16711936 & (16711935 & var14) * (-var11 + 256); + var12 += 16711680 & (var14 & '\uff00') * (256 - var11); + Drawing.screenBuffer[var13] = (var12 | var10) >>> 8; + } + + var8 = var5 >> 4; + var9 = var1 >> 4; + var11 = (var5 & 15) * (16 - (15 & var1)); + if (Drawing.left <= var8 && var8 < Drawing.right && var9 >= Drawing.top && Drawing.bottom > var9) { + var11 = (int) (Math.pow((double) var11 / 256.0D, 0.55D) * 256.0D); + var12 = '\uff00' & var0; + var12 *= var11; + var10 = var0 & 16711935; + var10 *= var11; + var12 &= 16711680; + var10 &= -16711936; + var13 = var8 + ShatteredPlansClient.SCREEN_WIDTH * var9; + var14 = Drawing.screenBuffer[var13]; + var10 += -16711936 & (16711935 & var14) * (256 - var11); + var12 += 16711680 & (var14 & '\uff00') * (-var11 + 256); + Drawing.screenBuffer[var13] = (var10 | var12) >>> 8; + } + + Drawing.horizontalLine((var4 >> 4) + 1, var1 >> 4, (var6 >> 4) - 2, var0, (16 - (15 & var1)) * 16); + var8 = var4 >> 4; + var9 = (var1 >> 4) + 1; + var11 = (var4 & 15) * (16 - (15 & var1)); + if (Drawing.left <= var8 && Drawing.right > var8 && Drawing.top <= var9 && Drawing.bottom > var9) { + var11 = (int) (256.0D * Math.pow((double) var11 / 256.0D, 0.55D)); + var12 = '\uff00' & var0; + var10 = var0 & 16711935; + var12 *= var11; + var12 &= 16711680; + var10 *= var11; + var10 &= -16711936; + var13 = var9 * ShatteredPlansClient.SCREEN_WIDTH + var8; + var14 = Drawing.screenBuffer[var13]; + var10 += (var14 & 16711935) * (-var11 + 256) & -16711936; + var12 += 16711680 & (-var11 + 256) * ('\uff00' & var14); + Drawing.screenBuffer[var13] = (var10 | var12) >>> 8; + } + + var8 = var5 >> 4; + var9 = 1 + (var1 >> 4); + var11 = (15 & var4) * (15 & var3); + if (var8 >= Drawing.left && Drawing.right > var8 && Drawing.top <= var9 && Drawing.bottom > var9) { + var11 = (int) (256.0D * Math.pow((double) var11 / 256.0D, 0.55D)); + var12 = '\uff00' & var0; + var10 = var0 & 16711935; + var12 *= var11; + var10 *= var11; + var12 &= 16711680; + var10 &= -16711936; + var13 = var9 * ShatteredPlansClient.SCREEN_WIDTH + var8; + var14 = Drawing.screenBuffer[var13]; + var10 += (256 - var11) * (var14 & 16711935) & -16711936; + var12 += (-var11 + 256) * (var14 & '\uff00') & 16711680; + Drawing.screenBuffer[var13] = (var12 | var10) >>> 8; + } + + Drawing.horizontalLine((var4 >> 4) + 1, (var1 >> 4) + 1, (var6 >> 4) - 2, var0, 16 * (15 & var1)); + } + + } else { + var8 = (var6 << 12) / var7; + var9 = var1 + 7 >> 4; + var10 = ((var9 << 4) - var1) * var8 + (var4 << 12); + var11 = -(7 + var1 & 15) + 16; + var12 = var9; + var13 = var10 >> 16; + int var17 = (-((var10 & 'ﷷ') >> 12) + 16) * var11; + int var16; + int var18; + int var19; + int var20; + if (var13 >= Drawing.left && Drawing.right > var13 && Drawing.top <= var9 && var9 < Drawing.bottom) { + var17 = (int) (256.0D * Math.pow((double) var17 / 256.0D, 0.55D)); + var18 = var0 & '\uff00'; + var16 = var0 & 16711935; + var18 *= var17; + var16 *= var17; + var18 &= 16711680; + var16 &= -16711936; + var19 = var9 * ShatteredPlansClient.SCREEN_WIDTH + var13; + var20 = Drawing.screenBuffer[var19]; + var16 += (16711935 & var20) * (-var17 + 256) & -16711936; + var18 += (-var17 + 256) * ('\uff00' & var20) & 16711680; + Drawing.screenBuffer[var19] = (var16 | var18) >>> 8; + } + + var14 = 1 + var13; + var18 = var11 * (15 & var10 >> 12); + int var21; + if (var14 >= Drawing.left && var14 < Drawing.right && Drawing.top <= var9 && Drawing.bottom > var9) { + var18 = (int) (Math.pow((double) var18 / 256.0D, 0.55D) * 256.0D); + var19 = var0 & '\uff00'; + var19 *= var18; + int i = var0 & 16711935; + i *= var18; + var19 &= 16711680; + i &= -16711936; + var20 = var9 * ShatteredPlansClient.SCREEN_WIDTH + var14; + var21 = Drawing.screenBuffer[var20]; + i += -16711936 & (var21 & 16711935) * (256 - var18); + var19 += (-var18 + 256) * ('\uff00' & var21) & 16711680; + Drawing.screenBuffer[var20] = (var19 | i) >>> 8; + } + + var9 = var3 + 7 >> 4; + var14 = var10 + var8; + var10 = (var5 << 12) + (-var3 + (var9 << 4)) * var8; + var11 = -(var3 + 7 & 15) + 16; + final int var15 = var10 >> 16; + var16 = var9; + var20 = (16 - (('\uf64c' & var10) >> 12)) * var11; + int var22; + int var23; + if (var15 >= Drawing.left && Drawing.right > var15 && var9 >= Drawing.top && Drawing.bottom > var9) { + var20 = (int) (256.0D * Math.pow((double) var20 / 256.0D, 0.55D)); + var21 = var0 & '\uff00'; + var21 *= var20; + var19 = var0 & 16711935; + var21 &= 16711680; + var19 *= var20; + var19 &= -16711936; + var22 = ShatteredPlansClient.SCREEN_WIDTH * var9 + var15; + var23 = Drawing.screenBuffer[var22]; + var19 += (var23 & 16711935) * (256 - var20) & -16711936; + var21 += (-var20 + 256) * (var23 & '\uff00') & 16711680; + Drawing.screenBuffer[var22] = (var19 | var21) >>> 8; + } + + int i = 1 + var15; + var20 = var11 * (15 & var10 >> 12); + if (i >= Drawing.left && Drawing.right > i && Drawing.top <= var9 && Drawing.bottom > var9) { + var20 = (int) (Math.pow((double) var20 / 256.0D, 0.55D) * 256.0D); + var21 = var0 & '\uff00'; + var21 *= var20; + var19 = var0 & 16711935; + var19 *= var20; + var21 &= 16711680; + var19 &= -16711936; + var22 = i + ShatteredPlansClient.SCREEN_WIDTH * var9; + var23 = Drawing.screenBuffer[var22]; + var19 += (-var20 + 256) * (var23 & 16711935) & -16711936; + var21 += (var23 & '\uff00') * (256 - var20) & 16711680; + Drawing.screenBuffer[var22] = (var21 | var19) >>> 8; + } + + var8 <<= 4; + ++var12; + + while (var16 > var12) { + i = var14 >> 16; + var20 = 256 - (var14 >> 8 & 255); + if (i >= Drawing.left && Drawing.right > i && var12 >= Drawing.top && Drawing.bottom > var12) { + var20 = (int) (256.0D * Math.pow((double) var20 / 256.0D, 0.55D)); + var21 = '\uff00' & var0; + var19 = var0 & 16711935; + var21 *= var20; + var19 *= var20; + var21 &= 16711680; + var19 &= -16711936; + var22 = i + ShatteredPlansClient.SCREEN_WIDTH * var12; + var23 = Drawing.screenBuffer[var22]; + var19 += -16711936 & (16711935 & var23) * (256 - var20); + var21 += ('\uff00' & var23) * (256 - var20) & 16711680; + Drawing.screenBuffer[var22] = (var19 | var21) >>> 8; + } + + i = (var14 >> 16) + 1; + var20 = 255 & var14 >> 8; + if (Drawing.left <= i && i < Drawing.right && Drawing.top <= var12 && var12 < Drawing.bottom) { + var20 = (int) (256.0D * Math.pow((double) var20 / 256.0D, 0.55D)); + var21 = '\uff00' & var0; + var21 *= var20; + var19 = var0 & 16711935; + var19 *= var20; + var21 &= 16711680; + var19 &= -16711936; + var22 = var12 * ShatteredPlansClient.SCREEN_WIDTH + i; + var23 = Drawing.screenBuffer[var22]; + var21 += 16711680 & (-var20 + 256) * (var23 & '\uff00'); + var19 += (var23 & 16711935) * (-var20 + 256) & -16711936; + Drawing.screenBuffer[var22] = (var21 | var19) >>> 8; + } + + var14 += var8; + ++var12; + } + + } + } + + private static void a306we(int var0, int var1, int var2, final int var3, int var5, final int var6) { + int var4 = 0; + final byte var8 = 0; + int var9 = 0; + int var10 = 0; + final int var11 = Drawing.left << 4; + final int var12 = Drawing.right << 4; + if (var2 > var0) { + final int var13 = var2; + var2 = var0; + var0 = var13; + final int i = var1; + var1 = var5; + var5 = i; + var4 = -var4 + 80; + } + + if (var2 < var12 && var12 < var0) { + var10 = (int) (65536L * (long) (var0 - var12) / (long) (-var2 + var0)); + } + + if (var11 > var2 && var0 > var11) { + var9 = (int) (65536L * (long) (-var2 + var11) / (long) (-var2 + var0)); + } + + final long var23 = var0 - var2; + final long var15 = var5 - var1; + var2 += (int) ((long) var9 * var23 >> 16); + var1 += (int) ((long) var9 * var15 >> 16); + var0 -= (int) ((long) var10 * var23 >> 16); + var5 -= (int) ((long) var10 * var15 >> 16); + final int i = Drawing.bottom << 4; + final int i1 = Drawing.top << 4; + int i2 = 0; + int i3 = 0; + int var17; + if (var1 > var5) { + var17 = var2; + var2 = var0; + var0 = var17; + var17 = var1; + var1 = var5; + var5 = var17; + var4 = 80 - var4; + } + + final long l = -var2 + var0; + final long i4 = var5 - var1; + if (var1 < i1 && var5 > i1) { + i3 = (int) ((long) (i1 - var1) * 65536L / (long) (var5 - var1)); + } + + if (var1 < i && i < var5) { + i2 = (int) ((long) (var5 - i) * 65536L / (long) (-var1 + var5)); + } + + var5 -= (int) (i4 * (long) i2 >> 16); + var1 += (int) ((long) i3 * i4 >> 16); + var2 += (int) (l * (long) i3 >> 16); + int var22 = var8 + var4 / 80; + var0 -= (int) (l * (long) i2 >> 16); + var4 %= 80; + + var17 = 1 + (int) Math.sqrt((var5 - var1) * (var5 - var1) + (-var2 + var0) * (var0 - var2)); + int var18 = var2; + + int var19; + for (var19 = var1; var4 < var17; var4 += 80) { + final int var20 = var4 * (-var2 + var0) / var17 + var2; + final int var21 = var1 + var4 * (-var1 + var5) / var17; + a022ar(var20, var18, var21, var19, (1 & var22) == 0 ? var3 : var6); + var18 = var20; + var19 = var21; + ++var22; + } + + a022ar(var0, var18, var5, var19, (1 & var22) != 0 ? var6 : var3); + } + + private static void a681be(int var1, final int var2, int var3, final int var4, int var5, int var6) { + int var0 = 0; + final int var7 = 5; + int var9; + if (var1 < var5) { + var9 = var5; + var5 = var1; + var1 = var9; + var9 = var3; + var3 = var6; + var6 = var9; + var0 = var7 - var0; + } + + final byte var8 = 0; + if (Drawing.left <= var1 && var5 <= Drawing.right) { + if (var3 > var6) { + var9 = var5; + var5 = var1; + var1 = var9; + var9 = var3; + var3 = var6; + var6 = var9; + var0 = var7 - var0; + } + + if (var6 >= Drawing.top && var3 <= Drawing.bottom) { + int var14 = var8 + var0 / var7; + var0 %= var7; + + var9 = (int) Math.sqrt((-var5 + var1) * (var1 - var5) + (var6 - var3) * (var6 - var3)) + 1; + int var10 = var5; + + int var11; + for (var11 = var3; var0 < var9; var0 += var7) { + final int var12 = (var1 - var5) * var0 / var9 + var5; + final int var13 = var3 + (-var3 + var6) * var0 / var9; + Drawing.line(var10, var11, var12, var13, (var14 & 1) == 0 ? var2 : var4); + var11 = var13; + var10 = var12; + ++var14; + } + + Drawing.line(var10, var11, var1, var6, (var14 & 1) != 0 ? var4 : var2); + } + } + } + + private static void drawSystemHatching(final int[] points, final int color, final int alpha) { + final int var3 = 256 - alpha; + final int var4 = color & 0xff00ff; + c797c(); + final int var5 = color & Drawing.GREEN; + a397c(points, points.length); + d797c(); + + while (a801c()) { + int var6 = _ce; + if (Drawing.left > var6) { + var6 = Drawing.left; + } + + int var7 = _ca; + if (Drawing.right < var7) { + var7 = Drawing.right; + } + + int var8 = (var6 & -8) - (7 & _ch); + var8 += 8 + (-8 & -var8 + var6); + + for (int var9 = Drawing.pixelIndex(var8, _ch); var7 > var8; var8 += 8) { + Drawing.screenBuffer[var9] = (16711935 & (16711935 & Drawing.screenBuffer[var9]) * var3 + var4 * alpha >>> 8) + (((Drawing.GREEN & Drawing.screenBuffer[var9]) * var3 + var5 * alpha & 16711680) >>> 8); + var9 += 8; + } + } + } + + private static void b093c(final int var0, int var1) { + while (true) { + if (var1 >= var0 + 8) { + boolean var2 = true; + + for (int var3 = var0 + 4; var3 < var1; var3 += 4) { + final int var4 = _cf[var3 - 4]; + final int var5 = _cf[var3]; + if (var4 > var5) { + var2 = false; + _cf[var3 - 4] = var5; + _cf[var3] = var4; + final int i = _cf[var3 - 2]; + _cf[var3 - 2] = _cf[var3 + 2]; + _cf[var3 + 2] = i; + final int i1 = _cf[var3 - 1]; + _cf[var3 - 1] = _cf[var3 + 3]; + _cf[var3 + 3] = i1; + } + } + + if (!var2) { + var1 -= 4; + continue; + } + } + + return; + } + } + + private static boolean a801c() { + int var0 = _cd; + int var1 = _cb2; + + int var3; + for (int var2 = _ch; var1 >= var0; var1 = var3) { + ++var2; + _ch = var2; + if (var2 >= Drawing.bottom) { + return false; + } + + int var4; + int var5; + for (var3 = _cc; var0 < _cg; var0 += 4) { + var4 = _cf[var0 + 1]; + if (var2 < var4) { + break; + } + + var5 = _cf[var0]; + final int var6 = _cf[var0 + 2]; + final int var7 = _cf[var0 + 3]; + final int var8 = (var6 - var5 << 16) / (var7 - var4); + final int var9 = (var5 << 16) + '耀'; + _cf[var0] = var9; + _cf[var0 + 2] = var8; + } + + for (var4 = var3; var4 < var0; var4 += 4) { + var5 = _cf[var4 + 3]; + if (var2 >= var5) { + _cf[var4] = _cf[var3]; + _cf[var4 + 1] = _cf[var3 + 1]; + _cf[var4 + 2] = _cf[var3 + 2]; + _cf[var4 + 3] = _cf[var3 + 3]; + var3 += 4; + } + } + + if (var3 == _cg) { + _cg = 0; + return false; + } + + b093c(var3, var0); + _cc = var3; + _cd = var0; + } + + _ce = _cf[var1] >> 16; + _ca = _cf[var1 + 4] >> 16; + _cf[var1] += _cf[var1 + 2]; + _cf[var1 + 4] += _cf[var1 + 6]; + var1 += 8; + _cb2 = var1; + return true; + } + + private static void a093c(final int var0, final int var1) { + if (var1 > var0 + 4) { + int var2 = var0; + final int var3 = _cf[var0]; + final int var4 = _cf[var0 + 1]; + final int var5 = _cf[var0 + 2]; + final int var6 = _cf[var0 + 3]; + + for (int var7 = var0 + 4; var7 < var1; var7 += 4) { + final int var8 = _cf[var7 + 1]; + if (var8 < var4) { + _cf[var2] = _cf[var7]; + _cf[var2 + 1] = var8; + _cf[var2 + 2] = _cf[var7 + 2]; + _cf[var2 + 3] = _cf[var7 + 3]; + var2 += 4; + _cf[var7] = _cf[var2]; + _cf[var7 + 1] = _cf[var2 + 1]; + _cf[var7 + 2] = _cf[var2 + 2]; + _cf[var7 + 3] = _cf[var2 + 3]; + } + } + + _cf[var2] = var3; + _cf[var2 + 1] = var4; + _cf[var2 + 2] = var5; + _cf[var2 + 3] = var6; + a093c(var0, var2); + a093c(var2 + 4, var1); + } + } + + private static void d797c() { + if (_cg < 0) { + _cb2 = 0; + _cd = 0; + _cc = 0; + _ch = 2147483646; + } else { + a093c(0, _cg); + int var0 = _cf[1]; + if (var0 < Drawing.top) { + var0 = Drawing.top; + } + + final byte var1 = 0; + + int var2; + for (var2 = 0; var2 < _cg; var2 += 4) { + final int var3 = _cf[var2 + 1]; + if (var0 < var3) { + break; + } + + final int var4 = _cf[var2]; + final int var5 = _cf[var2 + 2]; + final int var6 = _cf[var2 + 3]; + final int var7 = (var5 - var4 << 16) / (var6 - var3); + final int var8 = (var4 << 16) + '耀'; + _cf[var2] = var8 + (var0 - var3) * var7; + _cf[var2 + 2] = var7; + } + + _cc = var1; + _cd = var2; + _cb2 = var2; + _ch = var0 - 1; + } + } + + private static void c797c() { + _cg = 0; + } + + private static void a397c(final int[] var0, final int var2) { + final int var3 = _cg + (var2 << 1); + int var5; + if (_cf == null || _cf.length < var3) { + final int[] var4 = new int[var3]; + + for (var5 = 0; var5 < _cg; ++var5) { + assert _cf != null; + var4[var5] = _cf[var5]; + } + + _cf = var4; + } + + int var8 = var2 - 2; + + for (var5 = 0; var5 < var2; var5 += 2) { + final int var6 = var0[var8 + 1]; + final int var7 = var0[var5 + 1]; + if (var6 < var7) { + _cf[_cg++] = var0[var8]; + _cf[_cg++] = var6; + _cf[_cg++] = var0[var5]; + _cf[_cg++] = var7; + } else if (var7 < var6) { + _cf[_cg++] = var0[var5]; + _cf[_cg++] = var7; + _cf[_cg++] = var0[var8]; + _cf[_cg++] = var6; + } + + var8 = var5; + } + + } + + public static void a835ie(final Sprite var0, int var1, int var2) { + var1 += var0.x; + var2 += var0.y; + int var3 = Drawing.pixelIndex(var1, var2); + int var4 = 0; + int var5 = var0.height; + int var6 = var0.width; + int var7 = Drawing.width - var6; + int var8 = 0; + int var9; + if (var2 < Drawing.top) { + var9 = Drawing.top - var2; + var5 -= var9; + var2 = Drawing.top; + var4 += var9 * var6; + var3 += var9 * Drawing.width; + } + + if (var2 + var5 > Drawing.bottom) { + var5 -= var2 + var5 - Drawing.bottom; + } + + if (var1 < Drawing.left) { + var9 = Drawing.left - var1; + var6 -= var9; + var1 = Drawing.left; + var4 += var9; + var3 += var9; + var8 += var9; + var7 += var9; + } + + if (var1 + var6 > Drawing.right) { + var9 = var1 + var6 - Drawing.right; + var6 -= var9; + var8 += var9; + var7 += var9; + } + + if (var6 > 0 && var5 > 0) { + a650ie(Drawing.screenBuffer, var0.pixels, var4, var3, var6, var5, var7, var8); + } + } + + private static void a650ie(final int[] var0, final int[] var1, int var3, int var4, final int var5, final int var6, final int var7, final int var8) { + for (int var11 = -var6; var11 < 0; ++var11) { + for (int var12 = -var5; var12 < 0; ++var12) { + final int var2 = var1[var3++]; + if (var2 == 0) { + ++var4; + } else { + final int var9 = var0[var4]; + final int var10 = 256 - (var2 & 255); + var0[var4++] = ((var9 & 16711935) * var10 & -16711936 | (var9 & '\uff00') * var10 & 16711680) >> 8; + } + } + + var4 += var7; + var3 += var8; + } + + } + + public static void a194ie(final ArgbSprite var0, int var1, int var2, final int var3, final int var4, final int var5, final int var6) { + if (var6 != 0) { + var1 -= var0.x << 4; + var2 -= var0.y << 4; + final double var7 = (double) (var5 & '\uffff') * 9.587379924285257E-5D; + final int var9 = (int) Math.floor(Math.sin(var7) * (double) var6 + 0.5D); + final int var10 = (int) Math.floor(Math.cos(var7) * (double) var6 + 0.5D); + final int var11 = -var1 * var10 + -var2 * var9; + final int var12 = var1 * var9 + -var2 * var10; + final int var13 = ((var0.width << 4) - var1) * var10 + -var2 * var9; + final int var14 = -((var0.width << 4) - var1) * var9 + -var2 * var10; + final int var15 = -var1 * var10 + ((var0.height << 4) - var2) * var9; + final int var16 = var1 * var9 + ((var0.height << 4) - var2) * var10; + final int var17 = ((var0.width << 4) - var1) * var10 + ((var0.height << 4) - var2) * var9; + final int var18 = -((var0.width << 4) - var1) * var9 + ((var0.height << 4) - var2) * var10; + int var19; + int var20; + if (var11 < var13) { + var19 = var11; + var20 = var13; + } else { + var19 = var13; + var20 = var11; + } + + if (var15 < var19) { + var19 = var15; + } + + if (var17 < var19) { + var19 = var17; + } + + if (var15 > var20) { + var20 = var15; + } + + if (var17 > var20) { + var20 = var17; + } + + int var21; + int var22; + if (var12 < var14) { + var21 = var12; + var22 = var14; + } else { + var21 = var14; + var22 = var12; + } + + if (var16 < var21) { + var21 = var16; + } + + if (var18 < var21) { + var21 = var18; + } + + if (var16 > var22) { + var22 = var16; + } + + if (var18 > var22) { + var22 = var18; + } + + var19 >>= 12; + var20 = var20 + 4095 >> 12; + var21 >>= 12; + var22 = var22 + 4095 >> 12; + var19 += var3; + var20 += var3; + var21 += var4; + var22 += var4; + var19 >>= 4; + var20 = var20 + 15 >> 4; + var21 >>= 4; + var22 = var22 + 15 >> 4; + if (var19 < Drawing.left) { + var19 = Drawing.left; + } + + if (var20 > Drawing.right) { + var20 = Drawing.right; + } + + if (var21 < Drawing.top) { + var21 = Drawing.top; + } + + if (var22 > Drawing.bottom) { + var22 = Drawing.bottom; + } + + var20 = var19 - var20; + if (var20 < 0) { + var22 = var21 - var22; + if (var22 < 0) { + int var23 = var21 * Drawing.width + var19; + final int var24 = Drawing.width + var20; + final double var25 = 1.6777216E7D / (double) var6; + final int var27 = (int) Math.floor(Math.sin(var7) * var25 + 0.5D); + final int var28 = (int) Math.floor(Math.cos(var7) * var25 + 0.5D); + final int var29 = (var19 << 4) + 8 - var3; + final int var30 = (var21 << 4) + 8 - var4; + int var31 = (var1 << 8) - 2048 - (var30 * var27 >> 4); + int var32 = (var2 << 8) - 2048 + (var30 * var28 >> 4); + int var33; + int var34; + int var35; + int var36; + int var37; + int var38; + int var39; + if (var28 < 0) { + if (var27 < 0) { + for (var36 = var22; var36 < 0; var23 += var24) { + { + var37 = var31 + (var29 * var28 >> 4); + var38 = var32 + (var29 * var27 >> 4); + var39 = var20; + if ((var35 = var37 - (var0.width << 12)) >= 0) { + + var35 = (var28 - var35) / var28; + var39 = var20 + var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + if ((var35 = var38 - (var0.height << 12)) >= 0) { + + var35 = (var27 - var35) / var27; + var39 += var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + while (var39 < 0 && var37 >= -4096 && var38 >= -4096) { + var33 = var37 >> 12; + var34 = var38 >> 12; + a600ie(var0.pixels, var0.width, var0.height, var23, var33, var34, var37, var38); + ++var39; + var37 += var28; + var38 += var27; + ++var23; + } + + var23 -= var39; + } + + ++var36; + var31 -= var27; + var32 += var28; + } + } else { + for (var36 = var22; var36 < 0; var23 += var24) { + label252: + { + var37 = var31 + (var29 * var28 >> 4); + var38 = var32 + (var29 * var27 >> 4); + var39 = var20; + if ((var35 = var37 - (var0.width << 12)) >= 0) { + + var35 = (var28 - var35) / var28; + var39 = var20 + var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + if ((var35 = var38 + 4096) < 0) { + if (var27 == 0) { + var23 -= var39; + break label252; + } + + var35 = (var27 - 1 - var35) / var27; + var39 += var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + while (var39 < 0 && var37 >= -4096 && (var34 = var38 >> 12) < var0.height) { + var33 = var37 >> 12; + a600ie(var0.pixels, var0.width, var0.height, var23, var33, var34, var37, var38); + ++var39; + var37 += var28; + var38 += var27; + ++var23; + } + + var23 -= var39; + } + + ++var36; + var31 -= var27; + var32 += var28; + } + } + } else if (var27 < 0) { + for (var36 = var22; var36 < 0; var23 += var24) { + label254: + { + var37 = var31 + (var29 * var28 >> 4); + var38 = var32 + (var29 * var27 >> 4); + var39 = var20; + if ((var35 = var37 + 4096) < 0) { + if (var28 == 0) { + var23 -= var20; + break label254; + } + + var35 = (var28 - 1 - var35) / var28; + var39 = var20 + var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + if ((var35 = var38 - (var0.height << 12)) >= 0) { + + var35 = (var27 - var35) / var27; + var39 += var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + while (var39 < 0 && var38 >= -4096 && (var33 = var37 >> 12) < var0.width) { + var34 = var38 >> 12; + a600ie(var0.pixels, var0.width, var0.height, var23, var33, var34, var37, var38); + ++var39; + var37 += var28; + var38 += var27; + ++var23; + } + + var23 -= var39; + } + + ++var36; + var31 -= var27; + var32 += var28; + } + } else { + for (var36 = var22; var36 < 0; var23 += var24) { + label256: + { + var37 = var31 + (var29 * var28 >> 4); + var38 = var32 + (var29 * var27 >> 4); + var39 = var20; + if ((var35 = var37 + 4096) < 0) { + if (var28 == 0) { + var23 -= var20; + break label256; + } + + var35 = (var28 - 1 - var35) / var28; + var39 = var20 + var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + if ((var35 = var38 + 4096) < 0) { + if (var27 == 0) { + var23 -= var39; + break label256; + } + + var35 = (var27 - 1 - var35) / var27; + var39 += var35; + var37 += var28 * var35; + var38 += var27 * var35; + var23 += var35; + } + + while (var39 < 0 && (var33 = var37 >> 12) < var0.width && (var34 = var38 >> 12) < var0.height) { + a600ie(var0.pixels, var0.width, var0.height, var23, var33, var34, var37, var38); + ++var39; + var37 += var28; + var38 += var27; + ++var23; + } + + var23 -= var39; + } + + ++var36; + var31 -= var27; + var32 += var28; + } + } + + } + } + } + } + + private static void a600ie(final int[] var0, final int var1, final int var2, final int var3, final int var4, final int var5, int var6, int var7) { + final int var8 = var5 * var1 + var4; + var6 &= 4095; + var7 &= 4095; + final int var9; + final int var10; + int var13; + int var14; + if (var5 >= 0) { + if (var4 >= 0) { + var9 = var0[var8]; + var13 = (var9 & -16777216) != 0 ? (4096 - var6) * (4096 - var7) : 0; + } else { + var13 = 0; + var9 = 0; + } + + if (var4 < var1 - 1) { + var10 = var0[var8 + 1]; + var14 = (var10 & -16777216) != 0 ? var6 * (4096 - var7) : 0; + } else { + var14 = 0; + var10 = 0; + } + } else { + var14 = 0; + var13 = 0; + var10 = 0; + var9 = 0; + } + + final int var11; + final int var12; + int var15; + int var16; + if (var5 < var2 - 1) { + if (var4 >= 0) { + var11 = var0[var8 + var1]; + var15 = (var11 & -16777216) != 0 ? (4096 - var6) * var7 : 0; + } else { + var15 = 0; + var11 = 0; + } + + if (var4 < var1 - 1) { + var12 = var0[var8 + var1 + 1]; + var16 = (var12 & -16777216) != 0 ? var6 * var7 : 0; + } else { + var16 = 0; + var12 = 0; + } + } else { + var16 = 0; + var15 = 0; + var12 = 0; + var11 = 0; + } + + var13 >>= 16; + var14 >>= 16; + var15 >>= 16; + var16 >>= 16; + final int var17 = var13 + var14 + var15 + var16; + if (var17 >= 128) { + int var18 = (var9 & 16711935) * var13 + (var10 & 16711935) * var14; + var18 += (var11 & 16711935) * var15 + (var12 & 16711935) * var16; + int var19 = ((var9 & -16711936) >>> 8) * var13 + ((var10 & -16711936) >>> 8) * var14; + var19 += ((var11 & -16711936) >>> 8) * var15 + ((var12 & -16711936) >>> 8) * var16; + final int var20 = var19 >>> 24; + var18 = var18 >>> 8 & 16711935; + var19 &= Drawing.GREEN; + if (var20 != 0) { + final int var21 = 256 - var20; + final int var22 = Drawing.screenBuffer[var3]; + Drawing.screenBuffer[var3] = (var18 * var20 + (var22 & 16711935) * var21 & -16711936) + (var19 * var20 + (var22 & '\uff00') * var21 & 16711680) >>> 8; + } + } + + } + + private void c815(final StarSystem var1) { + this.drawSystemResources(var1); + this.drawSystemProjectHighlights(var1); + this.b815(var1); + if (this.unitScalingFactor < 1024.0F) { + this.d815(var1); + } + } + + private void drawSystems() { + if (this.unitScalingFactor > 1024.0F) { + final int maxRemainingGarrison = Arrays.stream(this.map.systems) + .mapToInt(var5 -> var5.remainingGarrison) + .filter(var5 -> var5 >= 0) + .max().orElse(0); + for (final StarSystem system : this.map.systems) { + if (isOnScreen(this.systemBounds[system.index])) { + this.drawSystem(system, maxRemainingGarrison); + if (system.hasDefensiveNet) { + this.drawDefensiveNet(system); + } + } + } + + this.drawWormholeConnections(); + + for (final StarSystem system : this.map.systems) { + if (isOnScreen(this.systemBounds[system.index])) { + Menu.SMALL_FONT.drawCentered( + Integer.toString(this.clonedRemainingGarrisons[system.index]), + this.systemDrawX[system.index] - 1, + this.systemDrawY[system.index] + 3, + Drawing.WHITE); + } + } + + for (final StarSystem system : this.map.systems) { + if (isOnScreen(this.systemBounds[system.index])) { + this.a527(system, false); + } + } + + this.i150(); + } else { + for (final StarSystem system : this.map.systems) { + if (isOnScreen(this.systemBounds[system.index])) { + this.b549(system); + this.drawSystemIcon(system); + if (this.unitScalingFactor < 330.0F && system.hasDefensiveNet) { + this.drawDefensiveNet(system); + } + } + } + + if (this.unitScalingFactor < 1024.0F) { + for (final StarSystem var10 : this.map.systems) { + this.a527(var10, false); + } + } + + for (final StarSystem system : this.map.systems) { + if (isOnScreen(this.systemBounds[system.index])) { + this.c815(system); + if (this.unitScalingFactor > 330.0F && system.hasDefensiveNet) { + this.drawDefensiveNet(system); + } + } + } + + if (this.unitScalingFactor < 1024.0F) { + for (final StarSystem system : this.map.systems) { + this.a527(system, true); + } + } + + this.drawWormholeConnections(); + this.i150(); + } + } + + private static boolean isOnScreen(final Rect bounds) { + return bounds.x1 <= ShatteredPlansClient.SCREEN_WIDTH && bounds.y1 <= ShatteredPlansClient.SCREEN_HEIGHT && bounds.x2 >= 0 && bounds.y2 >= 0; + } + + private MoveFleetsOrder findSelectedFleetOrder(final StarSystem system, final int x, final int y) { + if (this.unitScalingFactor > 1024.0F) { + for (final MoveFleetsOrder order : system.incomingOrders) { + if (this.localPlayer == order.player) { + final int midX = (this.systemDrawX[order.target.index] + this.systemDrawX[order.source.index]) / 2; + final int midY = (this.systemDrawY[order.source.index] + this.systemDrawY[order.target.index]) / 2; + if (MathUtil.isEuclideanDistanceLessThan(x - midX, y - midY, 9)) { + this._nb[0] = midX; + this._nb[1] = midY; + return order; + } + } + } + } else { + final int var5 = (int) system.incomingOrders.stream().filter(var6 -> var6.player == this.localPlayer).count(); + if (var5 != 0) { + final int var7; + if (this.unitScalingFactor < 330.0F) { + var7 = 12 * ((var5 - 1) / 11 + 1); + } else { + var7 = 12 * ((var5 - 1) / 12 + 1); + } + + final boolean[] var8 = new boolean[var7]; + final int[] var9 = new int[var7 * 2]; + + for (int var10 = 0; var10 < var7; ++var10) { + final double var11 = (double) (var10 * 2) * Math.PI / (double) var7; + if (this.unitScalingFactor < 330.0F && var11 >= 4.4505895925855405D && var11 <= 4.97418836818384D) { + var8[var10] = true; + var9[2 * var10] = -1; + var9[1 + 2 * var10] = -1; + } + + final double var13 = Math.sin(var11); + final double var15 = Math.cos(var11); + var9[var10 * 2] = (int) (var15 * 150.0D * this._wb) + this.systemDrawX[system.index]; + var9[var10 * 2 + 1] = (int) (150.0D * this._wb * var13) + this.systemDrawY[system.index]; + } + + for (final MoveFleetsOrder var6 : system.incomingOrders) { + if (var6.player == this.localPlayer) { + final StarSystem var33 = var6.source; + final StarSystem var34 = var6.target; + final int var12 = var33.index; + final int var35 = var34.index; + final int var14 = this.systemDrawX[var12]; + final int var36 = this.systemDrawY[var12]; + final int var16 = this.systemDrawX[var35]; + final int var17 = this.systemDrawY[var35]; + final double var20 = Math.sqrt((-var36 + var17) * (-var36 + var17) + (-var14 + var16) * (var16 - var14)); + final double var22 = (double) (var16 - var14) / var20; + final double var24 = (double) (var17 - var36) / var20; + final int var18 = var16 - (int) (var22 * this.zoomFactor * 150.0D); + final int var19 = -((int) (this.zoomFactor * 150.0D * var24)) + var17; + final int var26 = this.a357(var18, var9, var8, var36, var24, var19, var14, var22); + final int i = var9[2 * var26 + 1]; + final int i1 = var9[var26 * 2]; + if (this.unitScalingFactor < 700.0F && var7 <= 12) { + if (ARROW_SHIP.height * ARROW_SHIP.height / 4 >= MathUtil.euclideanDistanceSquared(-i1 + x, -i + y)) { + this._nb[0] = i1; + this._nb[1] = i; + return var6; + } + } else { + final int var27 = var14 + (int) ((double) this._Hb * var22); + final int var28 = var36 + (int) ((double) this._Hb * var24); + int var29 = (i1 + var27) / 2; + int var30 = (var28 + i) / 2; + final double sqrt = Math.sqrt((var28 - i) * (-i + var28) + (var27 - i1) * (-i1 + var27)); + var29 = (int) ((double) var29 + -var24 * sqrt / 10.0D); + var30 = (int) ((double) var30 + var22 * sqrt / 10.0D); + if ((-var30 + y) * (y - var30) + (-var29 + x) * (-var29 + x) < 81) { + this._nb[0] = var29; + this._nb[1] = var30; + return var6; + } + } + } + } + } + } + return null; + } + + private void i150() { + if (this._rb != null) { + if (this.unitScalingFactor <= 1024.0F) { + final int var2 = (int) this._rb.target.incomingOrders.stream() + .filter(var3 -> this.localPlayer == var3.player).count(); + if (var2 == 0) { + return; + } + + final int var4; + if (this.unitScalingFactor >= 330.0F) { + var4 = 12 + (var2 - 1) / 12 * 12; + } else { + var4 = 12 * ((var2 - 1) / 11) + 12; + } + + int var5 = 0; + int var6 = 0; + int var15; + int var16; + if (this.unitScalingFactor < 700.0F && var4 <= 12) { + var5 = this._ub[0]; + var6 = this._ub[1]; + } else { + final boolean[] var7 = new boolean[var4]; + final int[] var8 = new int[2 * var4]; + + for (int var9 = 0; var4 > var9; ++var9) { + final double var10 = Math.PI * (double) (var9 * 2) / (double) var4; + if (this.unitScalingFactor < 330.0F && var10 >= 4.4505895925855405D && var10 <= 4.97418836818384D) { + var7[var9] = true; + var8[var9 * 2] = -1; + var8[var9 * 2 + 1] = -1; + } + + final double var12 = Math.sin(var10); + final double var14 = Math.cos(var10); + var8[2 * var9] = (int) (150.0D * this._wb * var14) + this.systemDrawX[this._rb.target.index]; + var8[1 + var9 * 2] = (int) (150.0D * this._wb * var12) + this.systemDrawY[this._rb.target.index]; + } + + for (final MoveFleetsOrder var3 : this._rb.target.incomingOrders) { + if (var3.player == this.localPlayer) { + final StarSystem var29 = var3.source; + final StarSystem var31 = var3.target; + final int var11 = var29.index; + final int var33 = var31.index; + final int var13 = this.systemDrawX[var11]; + final int var35 = this.systemDrawY[var11]; + var15 = this.systemDrawX[var33]; + var16 = this.systemDrawY[var33]; + final double var17 = Math.sqrt((var16 - var35) * (var16 - var35) + (-var13 + var15) * (var15 - var13)); + final double var19 = (double) (var15 - var13) / var17; + var5 = var15 - (int) (var19 * 150.0D * this.zoomFactor); + final double var21 = (double) (var16 - var35) / var17; + var6 = var16 - (int) (this.zoomFactor * 150.0D * var21); + final int var23 = this.a357(var5, var8, var7, var35, var21, var6, var13, var19); + var5 = var8[var23 * 2]; + var6 = var8[var23 * 2 + 1]; + if (var3 == this._rb) { + break; + } + } + } + } + + final int var25 = this.systemDrawX[this._rb.source.index]; + final int var27 = this.systemDrawY[this._rb.source.index]; + final double var30 = Math.sqrt((-var27 + var6) * (var6 - var27) + (-var25 + var5) * (-var25 + var5)); + final double var32 = (double) (-var25 + var5) / var30; + final double var34 = (double) (-var27 + var6) / var30; + var15 = (int) (var32 * (double) this._Hb) + var25; + var16 = var27 + (int) ((double) this._Hb * var34); + int var37; + if (var32 != 0.0D) { + if (var34 != 0.0D) { + double var18 = -var27 + var6; + if (var18 < 0.0D) { + var18 = -var18; + } + + var37 = (int) (32768.0D * Math.asin(var18 / var30) / Math.PI); + if (var32 >= 0.0D) { + if (var34 > 0.0D) { + var37 = 65536 - var37; + } + } else if (var34 < 0.0D) { + var37 = '耀' - var37; + } else { + var37 += 32768; + } + } else if (var32 <= 0.0D) { + var37 = 32768; + } else { + var37 = 0; + } + } else if (var34 > 0.0D) { + var37 = 49152; + } else { + var37 = 16384; + } + + if (var30 <= 1.0D + (this.zoomFactor * 300.0D + 0.5D - this._wb * 150.0D)) { + if (var37 == 0) { + this._Cb.draw(4 + var5 - this._Cb.width, var16 - 4); + } else if (var37 == 32768) { + this._Cb.i093(1 + (var5 - 4), 5 + var16 - this._Cb.height); + } else if (var37 >= 16384) { + if (var37 > 16384 && var37 < 32768) { + this._Ob.draw(var5 - 4, var6 - 4); + } else if (var37 > 32768 && var37 < 49152) { + this._K.i093(var5 + 1 - 4, 5 - this._K.height + var6); + } else if (var37 > 49152) { + this._Ob.i093(5 - this._Ob.width + var5, 1 + (4 - this._Ob.height) + var6); + } + } else { + this._K.draw(-this._K.width + var5 + 4, var6 - 4); + } + } else { + a070eo(false, var16, var6, TICKS_PER_ANIMATION_PHASE, var5, var15); + } + + if (this.unitScalingFactor < 700.0F && var4 <= 12) { + Drawing.strokeCircle(var5, var6, 30, Drawing.WHITE); + Drawing.fillCircle(var5, var6, 30, Drawing.WHITE, 92); + a194ie((ArgbSprite) this.localPlayer._n, ARROW_SHIP.width << 3, ARROW_SHIP.height << 3, var5 * 16, var6 * 16, 3800 + (var37 - 16384), 4096); + Drawing.fillCircle(var5, var6, 9, 0, 92); + Menu.SMALL_FONT.drawCentered(Integer.toString(this._rb.quantity), var5, var6 + 4, Drawing.WHITE); + FLEET_BUTTONS[0].draw(30 + (var5 - FLEET_BUTTONS[0].width / 2), -(FLEET_BUTTONS[0].height / 2) + var6); + FLEET_BUTTONS[1].draw(var5 - FLEET_BUTTONS[0].width / 2 - 30, var6 - FLEET_BUTTONS[0].height / 2); + FLEET_BUTTONS[2].draw(-(FLEET_BUTTONS[0].width / 2) + var5, var6 - (FLEET_BUTTONS[0].height / 2 - 30)); + } else { + final int var38 = this._ub[0]; + int var39 = this._ub[1]; + --var39; + Drawing.strokeCircle(var38, var39, 30, Drawing.WHITE); + Drawing.fillCircle(var38, var39, 30, Drawing.WHITE, 92); + a194ie((ArgbSprite) this.localPlayer._n, ARROW_SHIP.width << 3, ARROW_SHIP.height << 3, 16 * var38, 16 * var39, var37 - 16384, 4096); + Drawing.fillCircle(var38, var39, 9, 0, 92); + Menu.SMALL_FONT.drawCentered(Integer.toString(this._rb.quantity), var38, var39 + 4, Drawing.WHITE); + FLEET_BUTTONS[0].draw(30 + var38 - FLEET_BUTTONS[0].width / 2, -(FLEET_BUTTONS[0].height / 2) + var39); + FLEET_BUTTONS[1].draw(var38 - 30 - FLEET_BUTTONS[0].width / 2, var39 - FLEET_BUTTONS[0].height / 2); + FLEET_BUTTONS[2].draw(-(FLEET_BUTTONS[0].width / 2) + var38, 30 + (var39 - FLEET_BUTTONS[0].height / 2)); + } + } else { + final int var2 = this._ub[0]; + int var24 = this._ub[1]; + --var24; + final int var4 = this.systemDrawX[this._rb.target.index] - this.systemDrawX[this._rb.source.index]; + final int var5 = this.systemDrawY[this._rb.target.index] - this.systemDrawY[this._rb.source.index]; + int var6; + if (var4 != 0) { + if (var5 == 0) { + if (var4 <= 0) { + var6 = 32768; + } else { + var6 = 0; + } + } else { + int var25 = var5; + final double var28 = Math.sqrt(MathUtil.euclideanDistanceSquared(var4, var5)); + if (var5 < 0) { + var25 = -var5; + } + + var6 = (int) (Math.asin((double) var25 / var28) * 32768.0D / Math.PI); + if (var4 < 0) { + if (var5 < 0) { + var6 = -var6 + '耀'; + } else { + var6 += 32768; + } + } else if (var5 > 0) { + var6 = 65536 - var6; + } + } + } else if (var5 <= 0) { + var6 = 16384; + } else { + var6 = 49152; + } + + Drawing.strokeCircle(var2, var24, 30, Drawing.WHITE); + Drawing.fillCircle(var2, var24, 30, Drawing.WHITE, 92); + a194ie((ArgbSprite) this.localPlayer._n, ARROW_SHIP.width << 3, ARROW_SHIP.height << 3, var2 * 16, 16 * var24, var6 - 16384, 4096); + Drawing.fillCircle(var2, var24, 9, 0, 92); + Menu.SMALL_FONT.drawCentered(Integer.toString(this._rb.quantity), var2, 4 + var24, Drawing.WHITE); + FLEET_BUTTONS[0].draw(var2 + (30 - FLEET_BUTTONS[0].width / 2), -(FLEET_BUTTONS[0].height / 2) + var24); + FLEET_BUTTONS[1].draw(-(FLEET_BUTTONS[0].width / 2) + (var2 - 30), var24 - FLEET_BUTTONS[0].height / 2); + FLEET_BUTTONS[2].draw(var2 - FLEET_BUTTONS[0].width / 2, -(FLEET_BUTTONS[0].height / 2) + 30 + var24); + } + + } + } + + public void tick(final Collection turnEvents) { + if (this.isAnimatingViewport) { + final float var3 = this.targetScrollPosnX - this.mapScrollPosnX; + final float var4 = this.targetScrollPosnY - this.mapScrollPosnY; + final float var5 = this.targetZoomFactor - this.unitScalingFactor; + this.isAnimatingViewport = Math.abs(var3) > 1.0F || Math.abs(var4) > 1.0F || Math.abs(var5) > 1.0F; + this.mapScrollPosnX += 0.1F * var3; + this.mapScrollPosnY += 0.1F * var4; + this.unitScalingFactor += 0.1F * var5; + } + + this.a487(); + + for (final CombatExplosion explosion : this.combatExplosions) { + explosion.ticksAlive++; + final int index = explosion.system.index; + final int dx = this.systemDrawX[index] - ShatteredPlansClient.SCREEN_CENTER_X; + final int dy = this.systemDrawY[index] - ShatteredPlansClient.SCREEN_CENTER_Y; + final float distance = MathUtil.euclideanDistance(dx, dy, this.unitScalingFactor) / 300.0F; + explosion.sound.setVolume((int) ((float) (Sounds.soundVolume * Sounds.SFX_EXPLOSION.volume << 6) / (distance * 96.0F))); + } + this.combatExplosions.removeIf(explosion -> explosion.ticksAlive == CombatExplosion.LIFETIME); + + this.tickAnimations(turnEvents); + this.gameUI.tick(); + + uiPulseCounter = (ShatteredPlansClient.currentTick % 64) * 8; + if (uiPulseCounter > 256) { + uiPulseCounter = 512 - uiPulseCounter; + } + } + + private void a679() { + for (final CombatEngagementAnimationState var4 : this.combatEngagements) { + final StarSystem var6 = var4.system; + final int var7 = var6.index; + final byte var8 = 20; + if (this.unitScalingFactor >= 1024.0F) { + final int var10 = -10 + this.systemDrawY[var7]; + final int var26 = this.animationTick / 20 % var4.players.length; + final int var9 = this.systemDrawX[var7] - (10); + final Player var27 = var4.players[var26]; + final Sprite var11 = var27 == null ? ShatteredPlansClient._wab : var27._e; + var11.c115(var9 - 1, var10 - 1, var8, var8); + final Sprite bi_ = var4.ownerAtCombatStart == null ? ShatteredPlansClient._fmb : var4.ownerAtCombatStart._o; + bi_.draw(-1 - (bi_.width >> 1) + var8 + var9, -(bi_.height >> 1) + (var8 + var10 - 1)); + } else { + drawSystemHex(this.systemHexes[var6.index], this.clonedSystemOwners[var6.index] != null ? this.clonedSystemOwners[var6.index].darkColor : 4210752, 160); + final Player[] var12 = new Player[var4.players.length]; + final int[] var13 = new int[var4.players.length]; + + for (int var14 = 0; var14 < var12.length; ++var14) { + var13[var14] = var4.players[var14] == null ? var4.fleetsAtCombatStart[var4.fleetsAtCombatStart.length - 1] : var4.fleetsAtCombatStart[var14]; + var12[var14] = var4.players[var14]; + } + + ArrayUtil.sortScored(var12, var13); + final Player[] var28 = new Player[var12.length]; + final int var15 = (var28.length - 1) / 2; + var28[var15] = var12[0]; + boolean var16 = true; + int var17 = 1; + + int var18; + for (var18 = 1; var12.length > var18; ++var18) { + var28[(var16 ? var17 : -var17) + var15] = var12[var18]; + if (!var16) { + ++var17; + } + + var16 = !var16; + } + + var18 = (int) (this._wb * 200.0D); + int var19 = (int) (345.0D * this._wb); + if (var19 > 30 * var12.length) { + var19 = 30 * var12.length; + } + + final int var20 = -(var19 / 2) + this.systemDrawX[var6.index]; + final byte var21 = 5; + final int var22 = this.unitScalingFactor >= 700.0F ? 0 : 10; + Drawing.fillRoundedRect(var20 - 2, -(var18 / 2) + this.systemDrawY[var6.index] - 5, 4 + var19, 10 + var18 + var22, var21, 0, 128); + var19 /= var12.length; + final int var23 = (int) ((double) this.systemDrawY[var6.index] + 0.5D * (double) var18); + + int var24; + for (var24 = 0; var28.length > var24; ++var24) { + this.a323(var28[var24], var23, var19, var18, var20 + var24 * var19, var4); + } + + if (this.unitScalingFactor < 700.0F) { + for (var24 = 0; var24 < var28.length; ++var24) { + int var25 = var28[var24] != null ? var4.fleets[var28[var24].index] : var4.fleets[var4.fleets.length - 1]; + if (var28[var24] == var4.victor) { + var25 += var4.fleetsAtCombatEnd; + } + + if (var28[var24] == var4.selectedPlayer && var25 < var4.fleetsAtCombatStart[var28[var24] == null ? var4.fleets.length - 1 : var28[var24].index] && var4.fleets[var4.victor == null ? var4.fleets.length - 1 : var4.victor.index] > 0) { + ++var25; + } + + Menu.SMALL_FONT.drawCentered(Integer.toString(var25), var19 / 2 + var20 + var19 * var24, Menu.SMALL_FONT.ascent / 2 + 5 + var23, Drawing.WHITE); + } + } + } + } + + } + + private void drawDefensiveNet(final StarSystem system) { + byte var3 = 0; + byte var4 = 0; + if (this.unitScalingFactor > 1024.0F) { + var4 = 1; + var3 = 1; + } + + final int var5 = (ShatteredPlansClient.currentTick + 5 * system.index) % 104; + if (system.type == StarSystem.Type.ALIEN_MINER || system.type == StarSystem.Type.ALIEN_SHIP || system.type == StarSystem.Type.ALIEN_BASE) { + final int var6 = this._xb[0].offsetX; + DEFNET_ANIM_LARGE[0].b115(-var3 + (this.systemDrawX[system.index] - var6 / 2), -var4 + this.systemDrawY[system.index] - var6 / 2, var6, var6); + if (var5 > 4 && var5 <= 48) { + this._xb[var5 / 4].drawAdd(-var3 - var6 / 2 + this.systemDrawX[system.index], -(var6 / 2) + this.systemDrawY[system.index] - var4, 128); + } + } else if (system.type == StarSystem.Type.PLANET_RINGED) { + final int var6 = this._Kb[0].offsetX; + DEFNET_ANIM_MID[0].b115(this.systemDrawX[system.index] - (var6 / 2 + var3), -(var6 / 2) + this.systemDrawY[system.index] - var4, var6, var6); + if (var5 > 4 && var5 <= 48) { + this._Kb[var5 / 4].drawAdd(-var3 - var6 / 2 + this.systemDrawX[system.index], -var4 - (var6 / 2) + this.systemDrawY[system.index], 128); + } + } else { + final int var6 = this._Mb[0].offsetX; + DEFNET_ANIM_SMALL[0].b115(-var3 - var6 / 2 + this.systemDrawX[system.index], -var4 - var6 / 2 + this.systemDrawY[system.index], var6, var6); + if (var5 > 4 && var5 <= 48) { + this._Mb[var5 / 4].drawAdd(-var3 - var6 / 2 + this.systemDrawX[system.index], this.systemDrawY[system.index] - var6 / 2 - var4, 128); + } + } + } + + private void a527(final StarSystem system, final boolean var1) { + int var10; + int var12; + int var13; + int var14; + int var15; + int var16; + int var17; + int var18; + if (this.unitScalingFactor > 1024.0F) { + final int[] var5 = new int[]{-14671840, -12566464, -10461088, -8355712}; + + for (final MoveFleetsOrder var6 : system.incomingOrders) { + final StarSystem var7 = var6.source; + final int var8 = var7.index; + final int var9 = system.index; + var10 = this.systemDrawX[var8]; + final int var11 = this.systemDrawY[var8]; + var12 = this.systemDrawX[var9]; + var13 = this.systemDrawY[var9]; + var14 = (int) Math.sqrt(MathUtil.euclideanDistanceSquared(var12 - var10, -var11 + var13)) + 1; + + for (var15 = ShatteredPlansClient.currentTick / 2 % 10; var14 > var15; var15 += 10) { + var16 = (1 + 2 * var15 * (var12 - var10)) / (var14 * 2) + var10; + var17 = var11 + (var15 * 2 * (var13 - var11) + 1) / (var14 * 2); + Drawing.drawCircleGradientAdd(var16 << 4, var17 << 4, 30, 3, var5); + } + + var15 = (var10 + var12) / 2; + var16 = (var11 + var13) / 2; + Drawing.fillCircle(var15, var16 - 1, 9, Drawing.WHITE, 192); + Menu.SMALL_FONT.drawCentered(Integer.toString(var6.quantity), var15, 3 + var16, 0); + if (var6 == this._rb) { + var17 = (var10 + var12) / 2; + var18 = (var13 + var11) / 2; + this._ub[0] = var17; + this._ub[1] = var18; + if (this._rb == this._Db) { + this._tb[0] = var17; + this._tb[1] = var18; + } + } + } + + } else { + final int var32 = (int) system.incomingOrders.stream().filter(var6 -> this.localPlayer == var6.player).count(); + if (var32 != 0) { + final int var33; + if (this.unitScalingFactor < 330.0F) { + var33 = 12 * (1 + (var32 - 1) / 11); + } else { + var33 = (1 + (var32 - 1) / 12) * 12; + } + + final boolean[] var34 = new boolean[var33]; + final int[] var35 = new int[2 * var33]; + + for (var10 = 0; var33 > var10; ++var10) { + final double var37 = Math.PI * (double) (var10 * 2) / (double) var33; + if (this.unitScalingFactor < 330.0F && var37 >= 4.4505895925855405D && var37 <= 4.97418836818384D) { + var34[var10] = true; + var35[2 * var10] = -1; + var35[1 + var10 * 2] = -1; + } + + final double var39 = Math.sin(var37); + final double var40 = Math.cos(var37); + var35[2 * var10] = this.systemDrawX[system.index] + (int) (var40 * 150.0D * this._wb); + var35[1 + 2 * var10] = this.systemDrawY[system.index] + (int) (150.0D * this._wb * var39); + } + + for (final MoveFleetsOrder var6 : system.incomingOrders) { + if (this.localPlayer == var6.player) { + final StarSystem var36 = var6.source; + final StarSystem var38 = var6.target; + var12 = var36.index; + var13 = var38.index; + var14 = this.systemDrawX[var12]; + var15 = this.systemDrawY[var12]; + var16 = this.systemDrawX[var13]; + var17 = this.systemDrawY[var13]; + final double var22 = Math.sqrt((var16 - var14) * (-var14 + var16) + (-var15 + var17) * (var17 - var15)); + final double var24 = (double) (-var14 + var16) / var22; + final int var20 = -((int) (150.0D * this.zoomFactor * var24)) + var16; + final double var26 = (double) (-var15 + var17) / var22; + final int var21 = var17 - (int) (var26 * 150.0D * this.zoomFactor); + final int var28 = this.a357(var20, var35, var34, var15, var26, var21, var14, var24); + final int i = var35[2 * var28]; + final int i1 = var35[2 * var28 + 1]; + double sqrt = Math.sqrt((i - var14) * (-var14 + i) + (i1 - var15) * (-var15 + i1)); + final double v = (double) (i1 - var15) / sqrt; + final double v1 = (double) (-var14 + i) / sqrt; + final int var19 = var15 + (int) ((double) this._Hb * v); + var18 = var14 + (int) ((double) this._Hb * v1); + int var41; + int var42; + if (var6 == this._rb) { + if (this.unitScalingFactor < 700.0F && var33 <= 12) { + this._ub[1] = i1; + this._ub[0] = i; + if (this._Db == this._rb) { + this._tb[0] = i; + this._tb[1] = i1; + } + } else { + var41 = (i + var18) / 2; + sqrt = Math.sqrt(MathUtil.euclideanDistanceSquared(-i + var18, var19 - i1)); + var42 = (i1 + var19) / 2; + var41 = (int) ((double) var41 + sqrt * -v / 10.0D); + var42 = (int) ((double) var42 + sqrt * v1 / 10.0D); + this._ub[0] = var41; + this._ub[1] = var42; + if (this._rb == this._Db) { + this._tb[0] = var41; + this._tb[1] = var42; + } + } + continue; + } + + if (v1 == 0.0D) { + if (v <= 0.0D) { + var41 = 16384; + } else { + var41 = 49152; + } + } else if (v == 0.0D) { + if (v1 <= 0.0D) { + var41 = 32768; + } else { + var41 = 0; + } + } else { + double var30 = -var15 + i1; + if (var30 < 0.0D) { + var30 = -var30; + } + + var41 = (int) (Math.asin(var30 / sqrt) * 32768.0D / Math.PI); + if (v1 >= 0.0D) { + if (v > 0.0D) { + var41 = -var41 + 65536; + } + } else if (v >= 0.0D) { + var41 += 32768; + } else { + var41 = -var41 + '耀'; + } + } + + if (var1) { + if (this.unitScalingFactor < 700.0F && var33 <= 12) { + a194ie((ArgbSprite) this.localPlayer._n, ARROW_SHIP.width << 3, ARROW_SHIP.height << 3, 16 * i, i1 * 16, var41 + 3800 - 16384, 4096); + Drawing.fillCircle(i, i1, 9, 0, 92); + Menu.SMALL_FONT.drawCentered(Integer.toString(var6.quantity), i, 4 + i1, Drawing.WHITE); + } else { + Drawing.drawCircleGradientAdd(16 * i, i1 * 16, 60, _rj.length - 1, new int[]{-65536, -65536, 0, -65536, -65536}); + } + + if (this.unitScalingFactor > 700.0F) { + var42 = (i + var18) / 2; + int var31 = (i1 + var19) / 2; + var42 -= (int) (v * (sqrt / 10.0D)); + var31 += (int) (v1 * (sqrt / 10.0D)); + Drawing.fillCircle(var42, var31 - 1, 9, Drawing.WHITE, 192); + Menu.SMALL_FONT.drawCentered(Integer.toString(var6.quantity), var42, 3 + var31, 0); + } + } else if (sqrt > 1.0D + (0.5D + this.zoomFactor * 300.0D - 150.0D * this._wb)) { + a070eo(false, var19, i1, 200, i, var18); + } else if (var41 == 0) { + this._Cb.draw(-this._Cb.width + i + 4, var19 - 4); + } else if (var41 == 32768) { + this._Cb.i093(i - 3, 4 + var19 - this._Cb.height + 1); + } else if (var41 >= 16384) { + if (var41 > 16384 && var41 < 32768) { + this._Ob.draw(i - 4, i1 - 4); + } else if (var41 > 32768 && var41 < 49152) { + this._K.i093(1 + i - 4, -this._K.height + i1 + 5); + } else if (var41 > 49152) { + this._Ob.i093(4 - this._Ob.width + i + 1, 4 + i1 - (this._Ob.height - 1)); + } + } else { + this._K.draw(4 + (i - this._K.width), i1 - 4); + } + } + } + } + } + } + + private void drawSystem(final StarSystem system, final int maxGarrison) { + final Player owner = this.clonedSystemOwners[system.index]; + + final int baseColor = owner == null ? 0x808080 : owner.color2; + final int color = Drawing.alphaOver(0, baseColor, 160 - (this.clonedRemainingGarrisons[system.index] * 160 / maxGarrison)); + drawSystemHex(this.systemHexes[system.index], color, 160); + + if (this.animationPhase == AnimationPhase.NOT_PLAYING) { + this.drawSystemHexWithHatching(system); + } + this.drawSystemProjectHighlights(system); + + if (system.type >= StarSystem.Type.ALIEN_MINER) { + this.drawSystemIcon(system); + final int radius = Math.max(Menu.SMALL_FONT.measureLineWidth(Integer.toString(this.clonedRemainingGarrisons[system.index])) + 1, 10); + Drawing.fillCircle( + this.systemDrawX[system.index] - 1, + this.systemDrawY[system.index] - 1, + radius, + Drawing.BLACK, + 128); + } + + if (system.name.equalsIgnoreCase("sol")) { + this.drawSystemIcon(system); + } + } + + public void a073(final Player[] var2) { + this._ib = var2; + this._cb = new int[this._ib.length][]; + this.j150(); + } + + private void a662(final List var1, final boolean var2, final boolean var3) { + if (this.animationTick <= TICKS_PER_ANIMATION_PHASE) { + + for (final MoveFleetsAnimationState var5 : var1) { + final int var6 = this.systemDrawX[var5.target.index]; + final int var7 = this.systemDrawY[var5.target.index]; + final int var8 = this.systemDrawX[var5.source.index]; + final int var9 = this.systemDrawY[var5.source.index]; + final double var10 = Math.sqrt((var6 - var8) * (-var8 + var6) + (var7 - var9) * (var7 - var9)); + final double var12 = (double) (var6 - var8) / var10; + final double var14 = (double) (-var9 + var7) / var10; + final int var16 = (int) (var12 * (double) this._Hb) + var8; + final int var17 = (int) (var14 * (double) this._Hb) + var9; + final int var18 = -((int) (var12 * (double) this._Hb)) + var6; + final int var19 = var7 - (int) (var14 * (double) this._Hb); + if (var2) { + final int var20 = this.animationTick * (-var16 + var18) * 16 / TICKS_PER_ANIMATION_PHASE + var16 * 16; + final int var21 = (-var17 + var19) * 16 * this.animationTick / TICKS_PER_ANIMATION_PHASE + 16 * var17; + final double var22 = Math.sqrt((var21 - 16 * var17) * (var21 - var17 * 16) + (var20 - 16 * var16) * (-(16 * var16) + var20)); + final double sqrt = Math.sqrt((-var17 + var19) * 256 * (-var17 + var19) + (-var16 + var18) * (var18 - var16) * 256); + final double var24 = sqrt / 2.0D; + final double var26 = 1.0D / var24; + final double var28 = sqrt / 10.0D - (var22 - var24) * (-var24 + var22) * var26 * 0.2D; + double var30 = (-var19 + var17) * 16; + double var32 = (var16 - var18) * 16; + var30 /= sqrt; + var32 /= sqrt; + final int var34 = var20 + (int) (var28 * var30); + final int var35 = -((int) (var32 * var28)) + var21; + int var39; + if (var12 != 0.0D) { + if (var14 != 0.0D) { + double var37 = (var19 - var17) * 16; + if (var37 < 0.0D) { + var37 = -var37; + } + + var39 = (int) (32768.0D * Math.asin(var37 / sqrt) / Math.PI); + if (var12 < 0.0D) { + if (var14 >= 0.0D) { + var39 += 32768; + } else { + var39 = -var39 + '耀'; + } + } else if (var14 > 0.0D) { + var39 = -var39 + 65536; + } + } else if (var12 <= 0.0D) { + var39 = 32768; + } else { + var39 = 0; + } + } else if (var14 <= 0.0D) { + var39 = 16384; + } else { + var39 = 49152; + } + + var39 -= 16384; + var39 = var39 + 7600 * this.animationTick / TICKS_PER_ANIMATION_PHASE - 3800; + final ArgbSprite var40 = (ArgbSprite) (var3 ? var5.player._b : var5.player._n); + a194ie(var40, ARROW_SHIP.width << 3, ARROW_SHIP.height << 3, var34, var35, var39, 4096); + Drawing.fillCircle(var34 >> 4, var35 >> 4, 9, 0, 92); + Menu.SMALL_FONT.drawCentered(Integer.toString(var5.quantity), var34 >> 4, (var35 >> 4) + 4, Drawing.WHITE); + } else { + a070eo(false, var17, var19, this.animationTick, var18, var16); + } + } + + } + } + + private void j150() { + Drawing.saveContext(); + + for (int var2 = 0; this._ib.length > var2; ++var2) { + final int var3 = this._ib[var2].color1; + this._ib[var2]._v = new ArgbSprite(FLEETS_ARROW_SHIP.offsetX, FLEETS_ARROW_SHIP.offsetY); + this._ib[var2]._v.installForDrawing(); + FLEETS_ARROW_SHIP.drawTinted2(0, 0, var3); + + int var4; + for (var4 = 0; var4 < FLEETS_ARROW_SHIP.pixels.length; ++var4) { + this._ib[var2]._v.pixels[var4] = (-16777216 & FLEETS_ARROW_SHIP.pixels[var4]) + (Drawing.WHITE & this._ib[var2]._v.pixels[var4]); + } + + this._ib[var2]._n = new ArgbSprite(ARROW_SHIP.offsetX, ARROW_SHIP.offsetY); + this._ib[var2]._n.installForDrawing(); + ARROW_SHIP.drawTinted(0, 0, var3); + + for (var4 = 0; var4 < ARROW_SHIP.pixels.length; ++var4) { + this._ib[var2]._n.pixels[var4] = (-16777216 & ARROW_SHIP.pixels[var4]) + (this._ib[var2]._n.pixels[var4] & Drawing.WHITE); + } + + this._ib[var2]._b = new ArgbSprite(ARROW_SHIP_DAMAGED.offsetX, ARROW_SHIP_DAMAGED.offsetY); + this._ib[var2]._b.installForDrawing(); + ARROW_SHIP_DAMAGED.drawTinted(0, 0, var3); + + for (var4 = 0; ARROW_SHIP_DAMAGED.pixels.length > var4; ++var4) { + this._ib[var2]._b.pixels[var4] = (Drawing.WHITE & this._ib[var2]._b.pixels[var4]) + (ARROW_SHIP_DAMAGED.pixels[var4] & -16777216); + } + + this._ib[var2]._o = new Sprite(10, 12); + this._ib[var2]._o.installForDrawing(); + SHIELD.drawTinted2(1, 1, var3); + this._ib[var2]._p = new Sprite(12, 12); + this._ib[var2]._p.installForDrawing(); + DEFENSE_GRID.drawTinted2(1, 1, var3); + this._ib[var2]._r = new Sprite(12, 12); + this._ib[var2]._r.installForDrawing(); + CHEVRON.drawTinted2(1, 1, var3); + this._ib[var2]._e = new Sprite(128, 128); + this._ib[var2]._e.installForDrawing(); + WARNING.drawTinted(0, 0, var3); + + for (var4 = 0; var4 < this._ib[var2]._e.pixels.length; ++var4) { + if (this._ib[var2]._e.pixels[var4] != 0) { + Drawing.addPixel(var4 % this._ib[var2]._e.width, var4 / this._ib[var2]._e.width, this._ib[var2].color1, 128); + this._ib[var2]._e.pixels[var4] = this._ib[var2]._e.pixels[var4] | -16777216; + } + } + + this._ib[var2]._c = new Sprite(18, 12); + this._ib[var2]._c.installForDrawing(); + HAMMER.drawTinted2(1, 1, var3); + this._ib[var2]._d = new Sprite(16, 10); + this._ib[var2]._d.installForDrawing(); + HAMMER.drawTinted2(0, 0, var3); + this._ib[var2]._o.f150(Drawing.WHITE); + this._ib[var2]._p.f150(Drawing.WHITE); + this._ib[var2]._r.f150(Drawing.WHITE); + this._ib[var2]._c.f150(Drawing.WHITE); + this._cb[var2] = new int[256]; + + for (var4 = 0; var4 < 256; ++var4) { + int var5 = var3 & 16711935; + int var6 = '\uff00' & var3; + var5 *= var4; + var6 *= var4; + var5 &= -16711936; + var6 &= 16711680; + this._cb[var2][var4] = (var6 | var5) >>> 8; + } + } + + Drawing.restoreContext(); + } + + private void a140(final StarSystem system) { + final int index = system.index; + final Player owner = this.clonedSystemOwners[index]; + if (owner == null) { + if (system == this.targetedSystem) { + this._Ib.draw((int) (-(this._wb * 345.0D / 2.0D) + (double) (1 + this.systemDrawX[index])), (int) (-(400.0D * this._wb / 2.0D) + (double) (1 + this.systemDrawY[index]))); + } else { + this._ob.draw((int) (-(this._wb * 345.0D / 2.0D) + (double) (1 + this.systemDrawX[index])), (int) (-(this._wb * 400.0D / 2.0D) + (double) (1 + this.systemDrawY[index]))); + } + } else if (system == this.targetedSystem) { + this._Ib.drawTinted2((int) (-(345.0D * this._wb / 2.0D) + (double) (this.systemDrawX[index] + 1)), (int) ((double) (this.systemDrawY[index] + 1) - this._wb * 400.0D / 2.0D), owner.color2); + } else { + this._ob.drawTinted2((int) ((double) (this.systemDrawX[index] + 1) - 345.0D * this._wb / 2.0D), (int) (-(this._wb * 400.0D / 2.0D) + (double) (this.systemDrawY[index] + 1)), owner.color2); + if (this.isTutorial && TutorialState._jau) { + this._Ib.draw((int) ((double) (this.systemDrawX[index] + 1) - 345.0D * this._wb / 2.0D), (int) ((double) (this.systemDrawY[index] + 1) - 400.0D * this._wb / 2.0D), uiPulseCounter); + } + } + } + + private void b549(final StarSystem system) { + if (this.animationPhase == AnimationPhase.NOT_PLAYING) { + this.drawSystemHexWithHatching(system); + } + this.a140(system); + } + + private int a357(final int var1, final int[] var2, final boolean[] var3, final int var4, final double var5, final int var8, final int var9, final double var10) { + int var12 = -1; + int var13 = Integer.MAX_VALUE; + + int var14; + int var15; + double var16; + for (var14 = 0; var3.length > var14; ++var14) { + if (!var3[var14]) { + var15 = (var8 - var2[var14 * 2 + 1]) * (-var2[2 * var14 + 1] + var8) + (var1 - var2[2 * var14]) * (-var2[var14 * 2] + var1); + var16 = (-((double) var4 * var10) + (double) var9 * var5 + (double) var2[1 + var14 * 2] * var10 - var5 * (double) var2[var14 * 2]) / (var5 * var5 + var10 * var10); + if (var16 >= -2.0 && (var15 < var13 || (double) var15 < (double) var13 && var16 < (-(var10 * (double) var4) + var5 * (double) var9 + var10 * (double) var2[2 * var12 + 1] - (double) var2[2 * var12] * var5) / (var5 * var5 + var10 * var10))) { + var12 = var14; + var13 = var15; + } + } + } + + if (var12 == -1) { + for (var14 = 0; var3.length > var14; ++var14) { + if (!var3[var14]) { + var15 = (-var2[2 * var14] + var1) * (-var2[var14 * 2] + var1) + (var8 - var2[var14 * 2 + 1]) * (-var2[var14 * 2 + 1] + var8); + if ((double) var13 * 0.35D > (double) var15) { + var12 = var14; + var13 = var15; + } + } + } + } + + if (var12 == -1) { + throw new RuntimeException("Unable to anchor incoming fleet."); + } else { + var3[var12] = true; + return var12; + } + } + + public void c326() { + if (this.selectedFleetOrder != null && this._Db == this.selectedFleetOrder) { + if (this._yb < 15 && this.unitScalingFactor < 700.0F && ++this._yb == 15) { + this._ub[0] = this._tb[0]; + this._ub[1] = this._tb[1]; + this._rb = this._Db; + } + } else if (this._yb > 0) { + if (--this._yb == 0) { + this._rb = null; + this._ub[1] = -1; + this._Db = this.selectedFleetOrder; + this._ub[0] = -1; + this._tb[0] = this._nb[0]; + this._tb[1] = this._nb[1]; + } + } else { + this._Db = this.selectedFleetOrder; + this._tb[0] = this._nb[0]; + this._tb[1] = this._nb[1]; + } + } + + private void drawSystemResources(final StarSystem system) { + if (system.type != StarSystem.Type.ALIEN_MINER && system.type != StarSystem.Type.ALIEN_SHIP && system.type != StarSystem.Type.ALIEN_BASE) { + final int index = system.index; + + final byte var4 = 24; + if (this.unitScalingFactor < 330.0F) { + final double var5 = TWO_HUNDRED_F * (float) this._Hb / ((float) this._n * this.unitScalingFactor); + this.resourceLightSprites[0][system.resources[0]].b115( + this.systemDrawX[index] - ((int) (var5 * 35.0D)) - this._Hb, + this.systemDrawY[index] - ((int) (var5 * (double) this.resourceLightSprites[0][0].height) / 2), + (int) ((double) this.resourceLightSprites[0][0].width * var5), + (int) ((double) this.resourceLightSprites[0][0].height * var5)); + this.resourceLightSprites[1][system.resources[1]].b115( + this.systemDrawX[index] - ((int) (COS_THIRTY_DEGREES * var5 * 32.0D)) - this._Hb, + this.systemDrawY[index] + (int) (var5 * 33.0D), + (int) ((double) this.resourceLightSprites[1][0].width * var5), + (int) ((double) this.resourceLightSprites[1][0].height * var5)); + this.resourceLightSprites[2][system.resources[2]].b115( + this.systemDrawX[index] - this._Hb + (int) (COS_THIRTY_DEGREES * 62.0D * var5) - 2, + (int) (33.0D * var5) + this.systemDrawY[index], + (int) ((double) this.resourceLightSprites[2][0].width * var5), + (int) ((double) this.resourceLightSprites[2][0].height * var5)); + this.resourceLightSprites[3][system.resources[3]].b115( + this.systemDrawX[index] + this._Hb + (int) (var5 * 4.0D), + this.systemDrawY[index] - ((int) (var5 * (double) this.resourceLightSprites[3][0].height) / 2), + (int) ((double) this.resourceLightSprites[3][0].width * var5), + (int) ((double) this.resourceLightSprites[3][0].height * var5)); + if (this.isTutorial && TutorialState._tdL) { + RES_SIDES[system.resources[0]].b050(-((int) (var5 * 35.0D)) - this._Hb + this.systemDrawX[index], -((int) (var5 * (double) this.resourceLightSprites[0][0].height) / 2) + this.systemDrawY[index], (int) ((double) this.resourceLightSprites[0][0].width * var5), (int) (var5 * (double) this.resourceLightSprites[0][0].height), uiPulseCounter); + RES_LOWS[system.resources[1]].b050(this.systemDrawX[index] + (-this._Hb - (int) (COS_THIRTY_DEGREES * 32.0D * var5)), this.systemDrawY[index] + (int) (33.0D * var5), (int) (var5 * (double) this.resourceLightSprites[1][0].width), (int) ((double) this.resourceLightSprites[1][0].height * var5), uiPulseCounter); + ArgbSprite var7 = (ArgbSprite) RES_LOWS[system.resources[2]]; + var7 = var7.copy(); + var7.flipHorizontal(); + var7.b050((int) (COS_THIRTY_DEGREES * var5 * 62.0D) + (this.systemDrawX[index] - this._Hb - 2), this.systemDrawY[index] + (int) (var5 * 33.0D), (int) ((double) this.resourceLightSprites[2][0].width * var5), (int) (var5 * (double) this.resourceLightSprites[2][0].height), uiPulseCounter); + ArgbSprite var8 = (ArgbSprite) RES_SIDES[system.resources[3]]; + var8 = var8.copy(); + var8.flipHorizontal(); + var8.b050((int) (var5 * 4.0D) + this.systemDrawX[index] + this._Hb, -((int) (var5 * (double) this.resourceLightSprites[3][0].height) / 2) + this.systemDrawY[index], (int) (var5 * (double) this.resourceLightSprites[3][0].width), (int) ((double) this.resourceLightSprites[3][0].height * var5), uiPulseCounter); + } + } else if (this.unitScalingFactor < 1024.0F) { + Drawing.fillCircle(this.systemDrawX[index], this.systemDrawY[index], 25, Drawing.BLACK, 128); + + if (system.resources[0] != 0) { + final Point[] points = new Point[2 + 2 * system.resources[0]]; + final int x = this.systemDrawX[index] << 4; + final int y = this.systemDrawY[index] << 4; + points[0] = new Point(x, y); + final int x1 = (this.systemDrawX[index] - ((int) ((double) var4 * COS_THIRTY_DEGREES))) << 4; + final int y1 = (this.systemDrawY[index] + 12) << 4; + points[1] = new Point(x1, y1); + + for (int i = 0; i < system.resources[0]; ++i) { + final int x2 = this.systemDrawX[index] - (int) ((double) var4 * Math.cos((double) (24 - (i * 12)) * Math.PI / 180.0D)) << 4; + final int y2 = this.systemDrawY[index] + (int) ((double) var4 * Math.sin((double) (24 - (i * 12)) * Math.PI / 180.0D)) << 4; + points[(i * 2) + 2] = new Point(x2, y2); + final int x3 = this.systemDrawX[index] - (int) ((double) var4 * Math.cos((double) (18 - (i * 12)) * Math.PI / 180.0D)) << 4; + final int y3 = this.systemDrawY[index] + (int) ((double) var4 * Math.sin((double) (18 - (i * 12)) * Math.PI / 180.0D)) << 4; + points[(i * 2) + 3] = new Point(x3, y3); + } + VectorDrawing.fillPolygon(points, RESOURCE_COLORS[0]); + } + + if (system.resources[1] != 0) { + final Point[] var9 = new Point[2 + 2 * system.resources[1]]; + final int x = this.systemDrawX[index] << 4; + final int y = this.systemDrawY[index] << 4; + var9[0] = new Point(x, y); + final int x1 = this.systemDrawX[index] << 4; + final int y1 = var4 + this.systemDrawY[index] << 4; + var9[1] = new Point(x1, y1); + + for (int var6 = 0; var6 < system.resources[1]; ++var6) { + final int x2 = this.systemDrawX[index] - (int) ((double) var4 * Math.sin((double) (6 + var6 * 12) * Math.PI / 180.0D)) << 4; + final int y2 = this.systemDrawY[index] + (int) (Math.cos((double) (6 + 12 * var6) * Math.PI / 180.0D) * (double) var4) << 4; + var9[2 + 2 * var6] = new Point(x2, y2); + final int x3 = this.systemDrawX[index] - (int) (Math.sin(Math.PI * (double) (12 + 12 * var6) / 180.0D) * (double) var4) << 4; + final int y3 = this.systemDrawY[index] + (int) (Math.cos(Math.PI * (double) (var6 * 12 + 12) / 180.0D) * (double) var4) << 4; + var9[2 + 2 * var6 + 1] = new Point(x3, y3); + } + + VectorDrawing.fillPolygon(var9, RESOURCE_COLORS[1]); + } + + if (system.resources[2] != 0) { + final Point[] var9 = new Point[2 + system.resources[2] * 2]; + final int x = this.systemDrawX[index] << 4; + final int y = this.systemDrawY[index] << 4; + var9[0] = new Point(x, y); + final int x1 = this.systemDrawX[index] << 4; + final int y1 = this.systemDrawY[index] + var4 << 4; + var9[1] = new Point(x1, y1); + + for (int var6 = 0; var6 < system.resources[2]; ++var6) { + final int x2 = this.systemDrawX[index] + (int) (Math.sin(Math.PI * (double) (6 + var6 * 12) / 180.0D) * (double) var4) << 4; + final int y2 = this.systemDrawY[index] + (int) (Math.cos((double) (6 + 12 * var6) * Math.PI / 180.0D) * (double) var4) << 4; + var9[var6 * 2 + 2] = new Point(x2, y2); + final int x3 = this.systemDrawX[index] + (int) ((double) var4 * Math.sin((double) (12 + 12 * var6) * Math.PI / 180.0D)) << 4; + final int y3 = this.systemDrawY[index] + (int) ((double) var4 * Math.cos((double) (12 + 12 * var6) * Math.PI / 180.0D)) << 4; + var9[2 + var6 * 2 + 1] = new Point(x3, y3); + } + + VectorDrawing.fillPolygon(var9, RESOURCE_COLORS[2]); + } + + if (system.resources[3] != 0) { + final Point[] var9 = new Point[2 * system.resources[3] + 2]; + final int x = this.systemDrawX[index] << 4; + final int y = this.systemDrawY[index] << 4; + var9[0] = new Point(x, y); + final int x1 = (int) (COS_THIRTY_DEGREES * (double) var4) + this.systemDrawX[index] << 4; + final int y1 = 12 + this.systemDrawY[index] << 4; + var9[1] = new Point(x1, y1); + + for (int var6 = 0; var6 < system.resources[3]; ++var6) { + final int x2 = this.systemDrawX[index] + (int) (Math.cos(Math.PI * (double) (24 - 12 * var6) / 180.0D) * (double) var4) << 4; + final int y2 = this.systemDrawY[index] + (int) ((double) var4 * Math.sin(Math.PI * (double) (-(12 * var6) + 24) / 180.0D)) << 4; + var9[2 + 2 * var6] = new Point(x2, y2); + final int x3 = this.systemDrawX[index] + (int) ((double) var4 * Math.cos(Math.PI * (double) (18 - var6 * 12) / 180.0D)) << 4; + final int y3 = this.systemDrawY[index] + (int) (Math.sin((double) (18 - 12 * var6) * Math.PI / 180.0D) * (double) var4) << 4; + var9[2 + var6 * 2 + 1] = new Point(x3, y3); + } + + VectorDrawing.fillPolygon(var9, RESOURCE_COLORS[3]); + } + } + } + } + + private void d815(final StarSystem var1) { + for (final ProjectOrder order : this.projectOrders) { + if (order.target == var1 || order.type == ResourceType.EXOTICS && order.source == var1) { + int var4 = this.systemDrawX[var1.index]; + int var5 = this.systemDrawY[var1.index]; + if (this.unitScalingFactor < 330.0F) { + var5 -= 7 * this._n / 10 + 44; + } + + if (order.type == ResourceType.METAL) { + var4 -= 13; + var5 -= 21; + } else if (order.type == ResourceType.BIOMASS) { + var4 -= 5; + var5 -= 24; + } else if (order.type == ResourceType.ENERGY) { + var5 -= 24; + var4 += 3; + } else { + var4 += 10; + var5 -= 20; + } + + _cos.drawTinted(var4, var5, RESOURCE_COLORS[order.type]); + } + } + } + + private void a599() { + final StarSystem[] var4 = this.map.systems; + for (final StarSystem var12 : var4) { + final int var8 = var12.index; + if (this.retreatTargets[var8]) { + if (this.localPlayer == null) { + if (var12.lastOwner == null) { + continue; + } + } else if (var12.lastOwner != this.localPlayer) { + continue; + } + + int var9 = this.animationTick; + if (var9 > 125) { + var9 = -this.animationTick + 150; + } + + if (var9 > 0) { + int var10 = 0; + int var11 = this._n; + if (var11 < 16) { + var11 = 16; + } + + if (var9 < 25) { + if (this.animationTick <= 125) { + var10 = MathUtil.ease(this.animationTick, 25, var11, 0); + } else { + var10 = MathUtil.ease(this.animationTick - 125, 25, 0, -var11); + } + + var11 = MathUtil.ease(var9, 25, var11 / 2, var11); + } + + SYSTEM_ICONS[4].b115(this.systemDrawX[var8] - var11, -var11 + this.systemDrawY[var8] + var10, 2 * var11, var11 * 2); + } + } + } + + this.a662(this.collapseRetreats, false, true); + this.a662(this.collapseRetreats, true, true); + } + + private void drawSystemHexWithHatching(final StarSystem system) { + final Player owner = this.clonedSystemOwners[system.index]; + if (owner == null) { + final boolean isAttacked = system.incomingOrders.stream() + .anyMatch(order -> order.player == this.localPlayer); + if (isAttacked && this.localPlayer != null) { + if (!this.canOwnSystem[system.index]) { + drawSystemHatching(this.systemHexes[system.index], Drawing.RED, 96); + } else if (this.willOwnSystem[system.index]) { + drawSystemHatching(this.systemHexes[system.index], Drawing.GREEN, 64); + } else { + drawSystemHatching(this.systemHexes[system.index], Drawing.YELLOW, 64); + } + } + + if (this.highlightedSystems[system.index] == SystemHighlight.NONE) { + return; + } + } + + final int var8 = owner == null ? 0x303030 : owner.darkColor; + final int[] var6 = a385qp(this._Qb[system.index]); + if (var6 != null) { + if (this.highlightedSystems[system.index] == SystemHighlight.SOURCE) { + drawSystemHex(var6, ((var8 & 0xfefefe) >> 1) + 0x004000 + ((var8 & 0xfcfcfc) >> 2), 192); + } else if (this.highlightedSystems[system.index] == SystemHighlight.TARGET) { + drawSystemHex(var6, ((var8 & 0xfefefe) >> 1) + 0x404040 + ((var8 & 0xfcfcfc) >> 2), 192); + } else { + drawSystemHex(var6, (var8 & 0x8f8f8f) << 1, 128); + } + + if (owner == this.localPlayer && this.localPlayer != null) { + if (!this.canOwnSystem[system.index]) { + drawSystemHatching(var6, Drawing.RED, this.systemCollapseStages[system.index] == 0 ? 192 : 96); + } else if (!this.willOwnSystem[system.index]) { + drawSystemHatching(var6, Drawing.YELLOW, this.possibleSystemCollapseStages[system.index] == 0 ? 128 : 64); + } + } + } + } + + private void b815(final StarSystem var1) { + final int var3 = var1.index; + final Player var4 = this.clonedSystemOwners[var3]; + final int var5 = var4 == null ? 8421504 : var4.color1; + + if (this.unitScalingFactor < 330.0F) { + GameUI.FACTION_RING_CENTER.drawTinted(-(GameUI.FACTION_RING_CENTER.width / 2) + this.systemDrawX[var1.index], -(7 * this._n / 10) + this.systemDrawY[var1.index] - 63, var5); + if (this.isTutorial && TutorialState._vcj) { + GameUI.FACTION_RING_CENTER.draw(-(GameUI.FACTION_RING_CENTER.width / 2) + this.systemDrawX[var1.index], -(7 * this._n / 10) + this.systemDrawY[var1.index] - 63, uiPulseCounter); + } + + GameUI.FACTION_RING_TAG.draw(-(GameUI.FACTION_RING_TAG.width / 2) + this.systemDrawX[var1.index], -(this._n * 7 / 10) + this.systemDrawY[var1.index] - 72); + Menu.SMALL_FONT.drawCentered(Integer.toString(this.clonedRemainingGarrisons[var3]), this.systemDrawX[var3], this.systemDrawY[var3] - 41 - 7 * this._n / 10, Drawing.WHITE); + Menu.SMALL_FONT.drawCentered(var1.name, this.systemDrawX[var3], this.systemDrawY[var3] - 7 * this._n / 10 - 11, Drawing.WHITE); + if (var1.score > 0 && var1.type < 6) { + Drawing.drawCircleGradientAdd(Menu._emc[0] + (this.systemDrawX[var3] << 4), (this.systemDrawY[var3] - (7 * this._n / 10 + 45) << 4) + Menu._pmDb[0], 50, 7, GameUI._hs); + if (var1.score == StarSystem.Score.NEUTRAL_HOMEWORLD) { + Drawing.drawCircleGradientAdd(Menu._emc[1] + (this.systemDrawX[var3] << 4), Menu._pmDb[1] + (this.systemDrawY[var3] - 45 - this._n * 7 / 10 << 4), 50, 7, GameUI._hs); + } + + if (var1.score == StarSystem.Score.PLAYER_HOMEWORLD) { + Drawing.drawCircleGradientAdd(Menu._emc[2] + (this.systemDrawX[var3] << 4), Menu._pmDb[2] + (this.systemDrawY[var3] + (-(this._n * 7 / 10) - 45) << 4), 50, 7, GameUI._hs); + Drawing.drawCircleGradientAdd((this.systemDrawX[var3] << 4) + Menu._emc[3], Menu._pmDb[3] + (this.systemDrawY[var3] - 7 * this._n / 10 - 45 << 4), 50, 7, GameUI._hs); + } + } + } else if (this.unitScalingFactor < 1024.0F) { + GameUI.FACTION_RING_CENTER.drawTinted(-(GameUI.FACTION_RING_CENTER.width / 2) + this.systemDrawX[var1.index], this.systemDrawY[var1.index] - GameUI.FACTION_RING_CENTER.height / 2, var5); + GameUI.FACTION_RING.draw(this.systemDrawX[var1.index] - GameUI.FACTION_RING.width / 2, this.systemDrawY[var1.index] - 3 - GameUI.FACTION_RING.height / 2); + Menu.SMALL_FONT.drawCentered(Integer.toString(this.clonedRemainingGarrisons[var3]), this.systemDrawX[var3], this.systemDrawY[var3] + 4, Drawing.WHITE); + if (var1.score > 0 && var1.type < 6) { + Drawing.drawCircleGradientAdd((this.systemDrawX[var3] << 4) + Menu._emc[0], (this.systemDrawY[var3] << 4) + Menu._pmDb[0], 50, 7, GameUI._hs); + if (var1.score == StarSystem.Score.NEUTRAL_HOMEWORLD) { + Drawing.drawCircleGradientAdd((this.systemDrawX[var3] << 4) + Menu._emc[1], Menu._pmDb[1] + (this.systemDrawY[var3] << 4), 50, 7, GameUI._hs); + } + + if (var1.score == StarSystem.Score.PLAYER_HOMEWORLD) { + Drawing.drawCircleGradientAdd(Menu._emc[2] + (this.systemDrawX[var3] << 4), Menu._pmDb[2] + (this.systemDrawY[var3] << 4), 50, 7, GameUI._hs); + Drawing.drawCircleGradientAdd((this.systemDrawX[var3] << 4) + Menu._emc[3], (this.systemDrawY[var3] << 4) + Menu._pmDb[3], 50, 7, GameUI._hs); + } + } + } + + } + + private void tickAnimations(final Collection turnEvents) { + final int ticksToAdvance = this.gameUI.animationSpeedDoubledButton.isActive() ? 2 : 1; + if (this.animationPhase == AnimationPhase.BUILD) { + final int buildPhaseDuration = Math.max(this.buildPhases != 0 ? (this.buildPhases * 125) + 25 : 0, TICKS_PER_ANIMATION_PHASE); + this.animationTick += ticksToAdvance; + if (this.animationTick >= buildPhaseDuration) { + this.advanceAnimationPhase(AnimationPhase.COMBAT, turnEvents); + } + } else if (this.animationPhase == AnimationPhase.COMBAT) { + for (final CombatEngagementAnimationState engagement : this.combatEngagements) { + while (ShatteredPlansClient.randomIntBounded(TICKS_PER_ANIMATION_PHASE + engagement.totalKills) >= TICKS_PER_ANIMATION_PHASE) { + this.combatExplosions.add(new CombatExplosion(engagement.system)); + } + + if (engagement.totalFleets >= 0) { + if (engagement.totalFleets == 0) { + if (ShatteredPlansClient.randomIntBounded(10) == 0) { + Arrays.fill(engagement.fleets, 0, engagement.players.length, 0); + engagement.totalFleets = -1; + } + } else { + while (ShatteredPlansClient.randomIntBounded(this.random, engagement.totalFleets + 40) >= 40) { + int roll = ShatteredPlansClient.randomIntBounded(this.random, engagement.totalFleets); + for (final Player player : engagement.players) { + final int playerIndex = player == null ? engagement.fleets.length - 1 : player.index; + final int playerFleets = engagement.fleets[playerIndex]; + roll -= playerFleets; + if (roll < 0) { + engagement.fleets[playerIndex]--; + engagement.totalFleets--; + break; + } + } + } + } + } + } + + this.animationTick += ticksToAdvance; + if (this.animationTick >= TICKS_PER_ANIMATION_PHASE) { + this.advanceAnimationPhase(AnimationPhase.POST_COMBAT, turnEvents); + } + } else if (this.animationPhase == AnimationPhase.POST_COMBAT) { + this.animationTick += ticksToAdvance; + if (this.animationTick >= 150) { + this.advanceAnimationPhase(AnimationPhase.RETREAT, turnEvents); + } + } else if (this.animationPhase == AnimationPhase.RETREAT) { + this.animationTick += ticksToAdvance; + if (this.animationTick >= TICKS_PER_ANIMATION_PHASE) { + this.advanceAnimationPhase(AnimationPhase.NOT_PLAYING, turnEvents); + this.gameUI.animationPlayingButton.deactivate(); + this.gameUI.animationPlayingButton.tooltip = StringConstants.TOOLTIP_ANIM_CLICK_TO_PLAY; + } + } + } + + private void a323(final Player var1, final int var2, final int var3, final int var4, final int var6, final CombatEngagementAnimationState var7) { + final int var8 = var1 == null ? var7.fleets.length - 1 : var1.index; + int var9 = var7.fleets[var8]; + if (var1 == var7.victor) { + var9 += var7.fleetsAtCombatEnd; + } + + if (var1 == var7.selectedPlayer && var9 < var7.fleetsAtCombatStart[var8] && var7.fleets[var7.victor != null ? var7.victor.index : this._ib.length] > 0) { + ++var9; + } + + int var10 = var3 - 2; + if (var10 > 20) { + var10 = 20; + } + + int var11 = var10 / 2; + if (var11 > 5) { + var11 = 5; + } + + final int var12 = var4 - var11 * 2; + int var13 = var12 * var7.fleetsAtCombatStart[var8] / var7.highestFleetsAtCombatStart; + if (var13 == 0) { + var13 = 1; + } + + var13 += var11 * 2; + Drawing.fillRoundedRect(-2 - var10 / 2 + var3 / 2 + var6, var2 - var13 - 2, var10 + 4, 4 + var13, 2 + var11, 0); + final int var14 = var1 != null ? var1.color1 : 8421504; + if (var1 == var7.ownerAtCombatStart && var7.system.hasDefensiveNet) { + Drawing.f669(-(var10 / 2) + var3 / 2 + var6 - 2, var2 - var13 - 2, 4 + var10, var13 + 4, 2 + var11, RESOURCE_COLORS[0]); + } else { + ShatteredPlansClient.a229ch(var14, 2 + var11, 4 + var10, var3 / 2 + var6 - var10 / 2 - 2, var2 - var13 - 2, 0, 4 + var13); + } + + int var15 = var12 * var9 / var7.highestFleetsAtCombatStart; + if (var15 != 0) { + var15 += 2 * var11; + Drawing.fillRoundedRect(-(var10 / 2) + var6 + var3 / 2, var2 - var15, var10, var15, var11, var14); + int var16 = var15 / 3; + if (var11 * 2 + 1 > var16) { + var16 = 1 + var11 * 2; + } + + Drawing.b370(-(var10 / 2) + var3 / 2 + var6, -var15 + var2, var10, var16, var11, var14); + final int[] var17 = new int[4]; + Drawing.saveBoundsTo(var17); + Drawing.setBounds(var6 - (-(var3 / 2) + var10 / 2), var2 - var13, var3 / 2 + var6 + var10 / 2, var2); + a835ie(COMBAT_HEX_WHITE, var6 + (var3 / 2 - var10 / 2), -var13 + var2); + Drawing.restoreBoundsFrom(var17); + } + } + + public void render(final Collection tannhauserLinks, final Collection projectOrders, final boolean showDesyncMessage) { + this.projectOrders = projectOrders; + this.tannhauserLinks = tannhauserLinks; + Menu.a487ai(); + + if (this._Nb != this._wb) { + this._Nb = this._wb; + Drawing.saveContext(); + final ArgbSprite var7 = new ArgbSprite(10, (int) (this._wb * 200.0D)); + var7.installForDrawing(); + + for (int var9 = 0; var9 < 10; ++var9) { + final int var10 = Drawing.WHITE - 218103808 * var9 - 2113929216; + Drawing.verticalLine(var9, 0, 200, var10); + } + + final ArgbSprite var8 = new ArgbSprite(15, (int) (200.0D * this._wb)); + var8.installForDrawing(); + + for (int var9 = 0; var9 < 15; ++var9) { + final int var10 = Drawing.WHITE + 285212672 * (-var9 + 15); + Drawing.verticalLine(var9, 0, 200, var10); + } + + final int var9 = (int) (0.5D + 345.0D * this._wb); + final int var10 = (int) (400.0D * this._wb + 0.5D); + this._ob = new ArgbSprite(var9, var10); + this._ob.installForDrawing(); + var7.draw(0, (int) (this._wb * 100.0D + 0.5D)); + var7.h093(var9 - 10, (int) (100.0D * this._wb + 0.5D)); + var7.a050(var10 - 5 - (int) (100.0D * this._wb * 0.5D + 0.5D), 4096, (int) (this._wb * 100.0D * COS_THIRTY_DEGREES) + 3, 10923); + var7.a050(-5 - (int) (0.5D + 0.5D * this._wb * 100.0D) + var10, 4096, var9 - 3 - (int) (100.0D * this._wb * COS_THIRTY_DEGREES), 21845); + var7.a050(4 + (int) (0.5D * this._wb * 100.0D), 4096, var9 - (int) (COS_THIRTY_DEGREES * 100.0D * this._wb) - 3, 43691); + var7.a050(4 + (int) (100.0D * this._wb * 0.5D), 4096, (int) (this._wb * 100.0D * COS_THIRTY_DEGREES) + 3, 54613); + this._Ib = new ArgbSprite(var9, var10); + this._Ib.installForDrawing(); + var8.draw(0, (int) (0.5D + this._wb * 100.0D)); + var8.h093(var9 - 15, (int) (0.5D + this._wb * 100.0D)); + var8.a050(-7 - (int) (0.5D * 100.0D * this._wb + 0.5D) + var10, 4096, (int) (COS_THIRTY_DEGREES * this._wb * 100.0D) + 3, 10923); + var8.a050(var10 - ((int) (0.5D + 0.5D * this._wb * 100.0D) + 7), 4096, -5 - (int) (COS_THIRTY_DEGREES * 100.0D * this._wb) + var9, 21845); + var8.a050((int) (0.5D * this._wb * 100.0D) + 6, 4096, var9 - 5 - (int) (COS_THIRTY_DEGREES * this._wb * 100.0D), 43691); + var8.a050((int) (0.5D * this._wb * 100.0D) + 6, 4096, (int) (COS_THIRTY_DEGREES * this._wb * 100.0D) + 3, 54613); + Drawing.restoreContext(); + + for (int var11 = 0; var10 * var9 > var11; ++var11) { + this._ob.pixels[var11] = Drawing.WHITE | this._ob.pixels[var11] << 8; + this._Ib.pixels[var11] = Drawing.WHITE | this._Ib.pixels[var11] << 8; + } + + final int var11 = -this._Hb - (int) (150.0D * this._wb) + (int) (300.0D * this.zoomFactor + 0.5D); + this._Cb = new ArgbSprite(var11 + 4, var11 / 10 + 8); + this._K = new ArgbSprite((int) (4.0D + (double) var11 * 0.5D), (int) (4.0D + COS_THIRTY_DEGREES * (double) var11)); + this._Ob = new ArgbSprite((int) (4.0D + (double) var11 * 0.5D), (int) (4.0D + COS_THIRTY_DEGREES * (double) var11)); + Drawing.saveContext(); + this._Cb.installForDrawing(); + a070eo(true, 4, 4, 200, var11, 0); + this._K.installForDrawing(); + a070eo(true, this._K.height - 1, 4, 200, var11 / 2, 0); + this._Ob.installForDrawing(); + a070eo(true, this._K.height - 1, 4, 200, 4, this._Ob.width - 1); + Drawing.restoreContext(); + if (this._xb == null) { + this._xb = new Sprite[13]; + this._Mb = new Sprite[13]; + this._Kb = new Sprite[13]; + } + + Drawing.saveContext(); + + for (int var12 = 0; var12 < this._xb.length; ++var12) { + int var13 = (int) (this.zoomFactor * (double) DEFNET_ANIM_LARGE[var12].offsetX); + if (var13 < 20 + GameUI.FACTION_RING.height) { + var13 = GameUI.FACTION_RING.height + 20; + } + + if (this.unitScalingFactor > 1024.0F && (double) var13 > 345.0D * this._wb * 0.9D) { + var13 = (int) (this._wb * 345.0D * 0.9D); + } + + this._xb[var12] = new Sprite(var13, var13); + this._xb[var12].installForDrawing(); + DEFNET_ANIM_LARGE[var12].b115(0, 0, var13, var13); + int i = (int) (0.8D * this.zoomFactor * (double) DEFNET_ANIM_MID[var12].offsetX); + if (i < 20 + GameUI.FACTION_RING.height) { + i = GameUI.FACTION_RING.height + 20; + } + + if (this.unitScalingFactor > 1024.0F && 0.9D * this._wb * 345.0D < (double) i) { + i = (int) (0.9D * 345.0D * this._wb); + } + + this._Kb[var12] = new Sprite(i, i); + this._Kb[var12].installForDrawing(); + DEFNET_ANIM_MID[var12].b115(0, 0, i, i); + int i1 = (int) (this.zoomFactor * (double) DEFNET_ANIM_SMALL[var12].offsetX); + if (i1 < 20 + GameUI.FACTION_RING.height) { + i1 = GameUI.FACTION_RING.height + 20; + } + + if (this.unitScalingFactor > 1024.0F && this._wb * 345.0D * 0.9D < (double) i1) { + i1 = (int) (this._wb * 345.0D * 0.9D); + } + + this._Mb[var12] = new Sprite(i1, i1); + this._Mb[var12].installForDrawing(); + DEFNET_ANIM_SMALL[var12].b115(0, 0, i1, i1); + } + + Drawing.restoreContext(); + } + + this.drawBackground(); + this.drawSystems(); + this.drawCombatAnimations(); + + if (showDesyncMessage) { + int alpha = (ShatteredPlansClient.currentTick << 3) & 510; + if (alpha >= 256) { + alpha = 511 - alpha; + } + Menu.FONT.drawCentered("Checksum", 320, 240, Drawing.RED, alpha); + Menu.FONT.drawCentered("Failure", 320, Menu.FONT.ascent + 240, Drawing.RED, alpha); + } + + this.gameUI.render(); + } + + @Override + public void a487() { + super.a487(); + this._Hb = this._n; + if (GameUI.FACTION_RING.width / 2 > this._Hb) { + this._Hb = GameUI.FACTION_RING.width / 2; + } + + this.zoomFactor = TWO_HUNDRED_F / this.unitScalingFactor; + if (this.unitScalingFactor > 700.0F) { + this._Hb = this._n; + } + + this._wb = this.zoomFactor * 0.8D; + if (this._Qb == null || this._Qb.length < this.map.systems.length) { + this._Qb = this.systemHexes.clone(); + } + + float var2 = 10.0F; + var2 *= 300.0F / this.unitScalingFactor; + final float var3 = (float) (COS_THIRTY_DEGREES * (double) var2); + final float var4 = (float) (0.5D * (double) var2); + + for (final int[] ints : this._Qb) { + ints[1] = (int) ((float) ints[1] + var2); + ints[2] = (int) ((float) ints[2] - var3); + ints[3] = (int) ((float) ints[3] + var4); + ints[4] = (int) ((float) ints[4] - var3); + ints[5] = (int) ((float) ints[5] - var4); + ints[7] = (int) ((float) ints[7] - var2); + ints[8] = (int) ((float) ints[8] + var3); + ints[9] = (int) ((float) ints[9] - var4); + ints[10] = (int) ((float) ints[10] + var3); + ints[11] = (int) ((float) ints[11] + var4); + } + } + + private MoveFleetsOrder findSelectedFleetOrder(final int x, final int y) { + this._Ab = false; + this._Gb = false; + this._Bb = false; + if (this._rb != null) { + if ((-this._ub[0] - (-30 - x)) * (x - (this._ub[0] - 30)) + (y - this._ub[1]) * (-this._ub[1] + y) < FLEET_BUTTONS[0].width * FLEET_BUTTONS[0].width / 4) { + this._Gb = true; + return this._rb; + } + if ((x - 30 - this._ub[0]) * (-30 - this._ub[0] + x) + (y - this._ub[1]) * (-this._ub[1] + y) < FLEET_BUTTONS[0].width * FLEET_BUTTONS[0].width / 4) { + this._Ab = true; + return this._rb; + } + if (MathUtil.euclideanDistanceSquared(y - this._ub[1] - 30, x - this._ub[0]) < FLEET_BUTTONS[0].width * FLEET_BUTTONS[0].width / 4) { + this._Bb = true; + return this._rb; + } + if (MathUtil.isEuclideanDistanceLessThan(x - this._ub[0], y - this._ub[1], 30)) { + return this._rb; + } + } + + if (this.targetedSystem != null) { + final MoveFleetsOrder order = this.findSelectedFleetOrder(this.targetedSystem, x, y); + if (order != null) { + return order; + } + } + + return Arrays.stream(this.map.systems) + .map(system -> this.findSelectedFleetOrder(system, x, y)) + .filter(Objects::nonNull) + .findFirst().orElse(null); + } + + private void b599() { + for (final BuildEvent var4 : this.buildEvents) { + final int var5 = this.animationTick - (var4.phase * 125); + if (var5 > 0 && var5 < 150) { + drawSystemHex(this.systemHexes[var4.system.index], 0, 64); + } + } + + + for (final BuildEvent var4 : this.buildEvents) { + final int var5 = this.animationTick - 125 * var4.phase; + if (var5 > 0 && var5 < 150) { + int var6 = var5; + if (var5 > 125) { + var6 = -var5 + 150; + } + + final int var7 = var4.system.index; + int var8 = this._n; + if (var4.projectType == -1) { + var8 = var8 * (this.largestFleetBuildQuantity + var4.fleetsBuilt * 3) / this.largestFleetBuildQuantity; + if (var8 < 12) { + var8 = 12; + } + } else if (var8 < 32) { + var8 = 32; + } + + int var9 = 0; + if (var6 < 25) { + if (var5 > 125) { + var9 = MathUtil.ease(var5 - 125, 25, 0, -var8); + } else { + var9 = MathUtil.ease(var5, 25, var8, 0); + } + + var8 = MathUtil.ease(var6, 25, var8 / 2, var8); + } + + if (var4.projectType == -1) { + if (var4.player != null) { + var4.player._d.a050(var9 + this.systemDrawY[var7], 4096 * var8 / HAMMER.width, this.systemDrawX[var7], this.animationTick % 25 * TICKS_PER_ANIMATION_PHASE); + } + } else { + SYSTEM_ICONS[var4.projectType].b115(-var8 + this.systemDrawX[var7], this.systemDrawY[var7] + var9 - var8, var8 * 2, var8 * 2); + } + } + } + + } + + private void a326() { + this.a662(this.combatRetreats, false, true); + this.a662(this.combatRetreats, true, true); + } + + private void drawCombatAnimations() { + for (final CombatExplosion var5 : this.combatExplosions) { + final int i = var5.system.index; + final int x = ((var5.x * this._n) >> 10) + (this.systemDrawX[i] << 4); + final int y = ((var5.y * this._n) >> 10) + (this.systemDrawY[i] << 4); + final int alpha = var5.ticksAlive < 6 + ? var5.ticksAlive * 40 + : 260 - (var5.ticksAlive * 2); + Drawing.drawCircleGradientAdd(x, y, (this._n + 4) * 2, alpha, Drawing.SHADES_OF_GRAY); + } + + if (this.animationPhase == AnimationPhase.BUILD) { + this.a662(this.fleetMovements, false, false); + this.a662(this.fleetMovements, true, false); + this.b599(); + } else if (this.animationPhase == AnimationPhase.COMBAT) { + this.a326(); + this.a679(); + } else if (this.animationPhase == AnimationPhase.POST_COMBAT) { + this.b326(); + } else if (this.animationPhase == AnimationPhase.RETREAT) { + this.a599(); + } + } + + public void b423() { + this._tb[0] = this._nb[0]; + this._tb[1] = this._nb[1]; + this._rb = this.selectedFleetOrder; + this._Db = this.selectedFleetOrder; + this._yb = 15; + this._ub[1] = this._nb[1]; + this._ub[0] = this._nb[0]; + } + + private void drawWormholeConnections() { + for (StarSystem system : this.map.systems) { + if (system.neighbors != null) { + for (final StarSystem neighbor : system.neighbors) { + if (neighbor.index >= system.index) { + if (MathUtil.isEuclideanDistanceGreaterThan(system.posnX - neighbor.posnX, system.posnY - neighbor.posnY, 210)) { + final int drawX1 = this.systemDrawX[system.index]; + final int drawY1 = this.systemDrawY[system.index]; + final int drawX2 = this.systemDrawX[neighbor.index]; + final int drawY2 = this.systemDrawY[neighbor.index]; + float dx = (float) (drawX2 - drawX1); + float dy = (float) (drawY2 - drawY1); + final float distance = MathUtil.euclideanDistance(dx, dy); + dx /= distance; + dy /= distance; + int var22 = 128; + if ((this.isTutorial && TutorialState._erg) || this.targetedSystem == system || this.targetedSystem == neighbor) { + var22 = 127 + (int) ((1.0D + Math.cos(Math.PI * (double) (ShatteredPlansClient.currentTick % 50) / 25.0D)) * 64.0D); + } + + TannhauserLink link = null; + for (final TannhauserLink link1 : this.tannhauserLinks) { + if (link1.system1 == system && link1.system2 == neighbor) { + link = link1; + break; + } + if (link1.system1 == neighbor && link1.system2 == system) { + link = link1; + system = neighbor; + break; + } + } + + final int threshold = (int) (170.0D * this.zoomFactor); + if (distance > (float) (threshold * 2)) { + final int var24 = link == null ? var22 * 0x10101 : var22 * 0x10001 + (var22 >> 1) * 256; + final int var25 = drawX1 + (int) (dx * (float) threshold); + final int var26 = drawY1 + (int) (dy * (float) threshold); + final int var27 = drawX2 - (int) (dx * (float) threshold); + final int var28 = drawY2 - (int) (dy * (float) threshold); + if (link != null && link.turnsLeft != 3) { + var22 = (link.turnsLeft - 1) * var22 / 2; + final int var29 = 0x10001 * var22 + 256 * (var22 >> 1); + if (ShatteredPlansClient.renderQuality.antialiasWormholeConnections) { + a306we(var27 << 4, var26 << 4, var25 << 4, var24, var28 << 4, var29); + } else { + a681be(var27 << 4, var24, var26 << 4, var29, var25 << 4, var28 << 4); + } + } else if (ShatteredPlansClient.renderQuality.antialiasWormholeConnections) { + a669tue(var26 << 4, var27 << 4, var25 << 4, var24, var28 << 4); + } else { + drawLine(var25 << 4, var26 << 4, var27 << 4, var28 << 4, var24); + } + } + } + } + } + } + } + } + + public void a115(final GameUI.PlacementMode mode, final int x, final int y) { + if (mode == GameUI.PlacementMode.MOVE_FLEET_DEST || mode == GameUI.PlacementMode.GATE_DEST) { + this._nb[1] = -1; + this.selectedFleetOrder = null; + this._nb[0] = -1; + this.targetedSystem = this.systemHexAtPoint(x, y); + } else { + this.selectedFleetOrder = this.findSelectedFleetOrder(x, y); + if (this.selectedFleetOrder == null) { + this.targetedSystem = this.systemHexAtPoint(x, y); + if (mode == GameUI.PlacementMode.MOVE_FLEET_SRC) { + ProjectOrder projectOrder = null; + if (this.targetedSystem != null) { + projectOrder = this.projectOrders.stream() + .filter(order -> order.player == this.localPlayer && (order.target == this.targetedSystem || order.source == this.targetedSystem)) + .findFirst().orElse(null); + } + + if (this.animationPhase == AnimationPhase.NOT_PLAYING) { + if (projectOrder == null) { + this.gameUI.setActionHint(StringConstants.HINT_SELECT_SRC); + } else { + this.gameUI.setActionHint(Strings.format(StringConstants.HINT_CANCEL_PROJECT, StringConstants.PROJECT_NAMES[projectOrder.type], this.targetedSystem.name)); + } + } + } + } else { + this.targetedSystem = null; + } + } + } + + private void b326() { + final StarSystem[] var4 = this.map.systems; + for (final StarSystem var6 : var4) { + final int var7 = var6.index; + if (var7 >= this.systemOwners.length) { + break; + } + + final Player var8 = this.systemOwners[var7]; + final Player var9 = this.clonedSystemOwners[var7]; + if (var8 != var9) { + final Sprite var14; + if (this.localPlayer == null) { + if (var9 == null) { + continue; + } + + var14 = SYSTEM_ICONS[5]; + } else if (var9 == this.localPlayer) { + var14 = SYSTEM_ICONS[5]; + } else { + if (var8 != this.localPlayer || this.localPlayer == var6.lastOwner) { + continue; + } + + var14 = SYSTEM_ICONS[4]; + } + + int var11 = this.animationTick; + if (var11 > 125) { + var11 = 150 - this.animationTick; + } + + int var12 = 0; + int var13 = this._n; + if (var13 < 16) { + var13 = 16; + } + + if (var11 < 25) { + if (this.animationTick <= 125) { + var12 = MathUtil.ease(this.animationTick, 25, var13, 0); + } else { + var12 = MathUtil.ease(this.animationTick - 125, 25, 0, -var13); + } + + var13 = MathUtil.ease(var11, 25, var13 / 2, var13); + } + + var14.b115(-var13 + this.systemDrawX[var7], this.systemDrawY[var7] + var12 - var13, 2 * var13, 2 * var13); + } + } + } + + private void drawSystemProjectHighlights(final StarSystem system) { + for (final ProjectOrder order : this.projectOrders) { + if (system == order.target || (order.type == ResourceType.EXOTICS && system == order.source)) { + if (this.unitScalingFactor < 330.0F) { + Drawing.drawCircleGradientAdd( + this.systemDrawX[system.index] << 4, + (this.systemDrawY[system.index] - ((this._n * 7) / 10) - 44) << 4, + 550, + 255, + this.projectHighlightColors[order.type]); + } else { + final int radius = MathUtil.clamp(this.unitScalingFactor < 1024.0F ? 450 : 150, (int) (this.zoomFactor * 1500.0D), 700); + final boolean var11 = this.unitScalingFactor > 1024.0F; + Drawing.drawCircleGradientAdd( + (this.systemDrawX[system.index] - (var11 ? 2 : 0)) << 4, + (this.systemDrawY[system.index] - (var11 ? 1 : 0)) << 4, + radius, + 255, + this.projectHighlightColors[order.type]); + } + } + } + } +} diff --git a/src/main/java/funorb/shatteredplans/client/game/MoveFleetsAnimationState.java b/src/main/java/funorb/shatteredplans/client/game/MoveFleetsAnimationState.java new file mode 100644 index 0000000..96f5b84 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/MoveFleetsAnimationState.java @@ -0,0 +1,19 @@ +package funorb.shatteredplans.client.game; + +import funorb.shatteredplans.game.MoveFleetsOrder; +import funorb.shatteredplans.game.Player; +import funorb.shatteredplans.map.StarSystem; + +public final class MoveFleetsAnimationState { + public final Player player; + public final int quantity; + public final StarSystem source; + public final StarSystem target; + + public MoveFleetsAnimationState(final MoveFleetsOrder order) { + this.player = order.player; + this.quantity = order.quantity; + this.source = order.source; + this.target = order.target; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/game/PlayerStats.java b/src/main/java/funorb/shatteredplans/client/game/PlayerStats.java new file mode 100644 index 0000000..761f94b --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/PlayerStats.java @@ -0,0 +1,97 @@ +package funorb.shatteredplans.client.game; + +import funorb.Strings; +import funorb.shatteredplans.StringConstants; + +public final class PlayerStats { + public final int[] production; + public final int _e; + public final int[] systems; + public final int[] fleets; + public int _l; + public int _x; + public int wastedResearch; + public int _m; + public int _t; + public int _a; + public int _v; + public int _A; + public int _y; + public int _u; + public int _q; + public int _w; + public int _i; + public int _o; + public int _r; + public int _z; + public int _s; + + public PlayerStats(final int var1) { + this._e = var1; + this.systems = new int[100]; + this.fleets = new int[100]; + this.production = new int[100]; + } + + public int[] b341() { + final int[] var2 = new int[16]; + var2[3] = this._t == 0 ? 0 : 200 * this._i / this._t; + var2[2] = -this._r; + var2[9] = -this._q; + var2[0] = this._A; + var2[7] = -this.wastedResearch; + var2[6] = this._s; + var2[11] = -this._a; + var2[4] = this._x; + var2[10] = this._y; + if (this._l == 0) { + var2[14] = -1; + var2[12] = -1; + var2[13] = -1; + } else { + var2[12] = (this._l + 2 * this._u) / (2 * this._l); + var2[13] = (2 * this._w + this._l) / (this._l * 2); + var2[14] = (this._l + 2 * this._z) / (2 * this._l); + } + + var2[15] = this._a != 0 ? (this._a + 201 * this._y) / ((this._y + this._a) * 2) : 100; + var2[5] = this._o; + var2[8] = this._m; + var2[1] = this._v; + return var2; + } + + public String[] a061() { + final String[] var2 = new String[16]; + var2[0] = Integer.toString(this._A); + var2[1] = Integer.toString(this._v); + var2[2] = Integer.toString(this._r); + if (this._t == 0) { + var2[3] = StringConstants.TEXT_NOT_AVAILABLE; + } else { + final int var3 = (this._i * 20 + this._t) / (this._t * 2); + var2[3] = var3 / 10 + StringConstants.TEXT_DECIMAL + var3 % 10; + } + + var2[4] = Integer.toString(this._x); + var2[5] = Integer.toString(this._o); + var2[6] = Integer.toString(this._s); + var2[7] = Integer.toString(this.wastedResearch); + var2[8] = Integer.toString(this._m); + var2[9] = Integer.toString(this._q); + var2[10] = Integer.toString(this._y); + var2[11] = Integer.toString(this._a); + if (this._l == 0) { + var2[14] = StringConstants.TEXT_NOT_AVAILABLE; + var2[12] = StringConstants.TEXT_NOT_AVAILABLE; + var2[13] = StringConstants.TEXT_NOT_AVAILABLE; + } else { + var2[12] = Strings.format(StringConstants.TEXT_PERCENTAGE, Integer.toString((this._l + this._u * 2) / (this._l * 2))); + var2[13] = Strings.format(StringConstants.TEXT_PERCENTAGE, Integer.toString((2 * this._w + this._l) / (2 * this._l))); + var2[14] = Strings.format(StringConstants.TEXT_PERCENTAGE, Integer.toString((this._l + 2 * this._z) / (this._l * 2))); + } + + var2[15] = Strings.format(StringConstants.TEXT_PERCENTAGE, Integer.toString(this._a == 0 ? 100 : (this._y * 201 + this._a) / (2 * (this._a + this._y)))); + return var2; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/game/StellarBombEvent.java b/src/main/java/funorb/shatteredplans/client/game/StellarBombEvent.java new file mode 100644 index 0000000..190eca1 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/StellarBombEvent.java @@ -0,0 +1,16 @@ +package funorb.shatteredplans.client.game; + +import funorb.shatteredplans.game.Player; +import funorb.shatteredplans.map.StarSystem; + +public final class StellarBombEvent implements TurnEventLog.Event { + public final Player player; + public final StarSystem target; + public final int kill; + + public StellarBombEvent(final Player player, final StarSystem target, final int kills) { + this.player = player; + this.target = target; + this.kill = kills; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/game/TickTimer.java b/src/main/java/funorb/shatteredplans/client/game/TickTimer.java new file mode 100644 index 0000000..0598a22 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/TickTimer.java @@ -0,0 +1,19 @@ +package funorb.shatteredplans.client.game; + +public final class TickTimer { + public final int createdTick; + public TickTimer next; + + public TickTimer(final int tick) { + this.createdTick = tick; + this.next = null; + } + + public void addNext(final int tick) { + TickTimer node = this; + while (node.next != null) { + node = node.next; + } + node.next = new TickTimer(tick); + } +} diff --git a/src/main/java/funorb/shatteredplans/client/game/TurnEventLog.java b/src/main/java/funorb/shatteredplans/client/game/TurnEventLog.java new file mode 100644 index 0000000..6e32dc9 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/TurnEventLog.java @@ -0,0 +1,71 @@ +package funorb.shatteredplans.client.game; + +import funorb.shatteredplans.game.GameState; +import funorb.shatteredplans.game.MoveFleetsOrder; +import funorb.shatteredplans.game.Player; +import funorb.shatteredplans.game.ProjectOrder; +import funorb.shatteredplans.map.StarSystem; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public final class TurnEventLog { + public final List events = new ArrayList<>(); + + public void addTannhauserEvent(final Player var4, final StarSystem var2, final StarSystem var3) { + this.events.add(new ProjectOrder(var4, var3, var2)); + } + + public void addMoveFleetsEvent(final StarSystem var6, final StarSystem var1, final Player var2, final int var5) { + this.events.add(new MoveFleetsOrder(var2, var6, var1, var5)); + } + + public void addFleetRetreatEvent(final StarSystem source, final StarSystem[] targets, final int[] quantities) { + final int retreatCount = (int) Arrays.stream(quantities).filter(quantity -> quantity != 0).count(); + if (retreatCount == 0) { + this.events.add(new FleetRetreatEvent(source)); + } else { + final StarSystem[] targets2 = new StarSystem[retreatCount]; + final int[] quantities2 = new int[retreatCount]; + int i = 0; + for (int j = 0; j < quantities.length; ++j) { + if (quantities[j] != 0) { + targets2[i] = targets[j]; + quantities2[i] = quantities[j]; + ++i; + } + } + + this.events.add(new FleetRetreatEvent(source, targets2, quantities2)); + } + } + + public void addFleetRetreatEvent(final StarSystem system) { + this.events.add(new FleetRetreatEvent(system)); + } + + public void addDefensiveNetEvent(final Player player, final StarSystem target) { + this.events.add(new ProjectOrder(GameState.ResourceType.METAL, player, target)); + } + + public void addStellarBombEvent(final Player player, final StarSystem target, final int kills) { + this.events.add(new StellarBombEvent(player, target, kills)); + } + + public CombatEngagementLog addCombatEngagement(final StarSystem system, final Player[] playersInvolved, final int[] fleetsAtCombatStart) { + final CombatEngagementLog combatLog = new CombatEngagementLog(system, playersInvolved, fleetsAtCombatStart); + this.events.add(combatLog); + return combatLog; + } + + public void addTerraformingEvent(final Player player, final StarSystem target) { + this.events.add(new ProjectOrder(GameState.ResourceType.BIOMASS, player, target)); + } + + public void addBuildFleetsEvent(final StarSystem system, final int quantity) { + this.events.add(new BuildFleetsEvent(system.owner, system, quantity)); + } + + public interface Event {} +} diff --git a/src/main/java/funorb/shatteredplans/client/game/TutorialObjective.java b/src/main/java/funorb/shatteredplans/client/game/TutorialObjective.java new file mode 100644 index 0000000..fa1e4e1 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/TutorialObjective.java @@ -0,0 +1,6 @@ +package funorb.shatteredplans.client.game; + +public final class TutorialObjective { + public String key; + public String description; +} diff --git a/src/main/java/funorb/shatteredplans/client/game/TutorialState.java b/src/main/java/funorb/shatteredplans/client/game/TutorialState.java new file mode 100644 index 0000000..203a441 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/game/TutorialState.java @@ -0,0 +1,1082 @@ +package funorb.shatteredplans.client.game; + +import funorb.Strings; +import funorb.awt.MouseState; +import funorb.client.TemplateDictionary; +import funorb.graphics.Drawing; +import funorb.graphics.Rect; +import funorb.graphics.Sprite; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.GameUI; +import funorb.shatteredplans.client.JagexApplet; +import funorb.shatteredplans.client.Menu; +import funorb.shatteredplans.client.ShatteredPlansClient; +import funorb.shatteredplans.client.TutorialMessage; +import funorb.shatteredplans.client.TutorialMessageId; +import funorb.shatteredplans.client.TutorialMessages; +import funorb.shatteredplans.game.CombinedForce; +import funorb.shatteredplans.game.ContiguousForce; +import funorb.shatteredplans.game.GameOptions; +import funorb.shatteredplans.game.GameState; +import funorb.shatteredplans.game.Player; +import funorb.shatteredplans.map.Map; +import funorb.shatteredplans.map.StarSystem; +import funorb.shatteredplans.map.generator.MapGenerationFailure; +import funorb.shatteredplans.map.generator.TutorialMapGenerator; +import funorb.util.MathUtil; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public final class TutorialState { + public static int stage; + public static boolean _jau; + public static boolean _tdL; + public static boolean _erg; + public static boolean _phg; + public static boolean _vcj; + public static boolean _sek; + public static Player _hod; + + private static ClientGameSession session; + private static Sprite[][] _spm; + private static TutorialMessage _hmq; + private static int _eie; + private static TutorialMessage _olg; + private static int _ef; + private static int _fkk; + private static int _klo; + private static TemplateDictionary templateDictionary; + private static List _aja; + private static List _qih; + private static boolean _isb; + private static int _gei; + private static TutorialMessage[] _jsb; + private static TutorialMapGenerator mapGenerator; + private static int _beh; + private static int _feB; + private static int[] _rgf; + private static int _dmgq; + private static int _oia; + private static Sprite[][] _oii; + private static Sprite[] _ehL; + private static int _tec; + private static int _tpb; + private static int _kpj; + private static int _jcr; + private static int _jbd; + private static StarSystem _idd; + private static int _ejm; + private static StarSystem _dd; + + private TutorialState() {} + + static void initialize(final ClientGameSession session) { + TutorialState.session = session; + templateDictionary = new TemplateDictionary(ShatteredPlansClient.templateDictionary); + mapGenerator = new TutorialMapGenerator(); + stage = 1; + _hmq = null; + _eie = -1; + _olg = null; + _ef = -1; + _fkk = -1; + _klo = -1; + _aja = new ArrayList<>(); + _qih = new ArrayList<>(); + _isb = false; + _jau = false; + _tdL = false; + _gei = 0; + _erg = false; + _phg = false; + _vcj = false; + _sek = false; + _jsb = new TutorialMessage[8]; + } + + public static void a529lp(final TutorialMessage var1) { + if (!_isb) { + _hmq = var1; + if (var1 == null) { + _tpb = _dmgq; + _feB = _jbd = _kpj + _jcr >> 1; + _oia = _beh; + a195qj(null); + } else { + a150sj(); + int var2 = var1._t; + int var3 = var1._b; + final int var4 = var1._j; + int var5 = var1._q; + + if (var1._q == -1) { + String var6 = templateDictionary.expand(var1.body); + int var7 = GameUI.breakLines(var6, Menu.SMALL_FONT, new int[]{var4 - 6 - 20}); + var5 = 34 + Menu.SMALL_FONT.descent + var7 * 13; + _ehL = new Sprite[var7]; + if (var1.objectives != null) { + final TutorialObjective[] var8 = var1.objectives; + + for (final TutorialObjective var10 : var8) { + var6 = templateDictionary.expand(var10.description); + var7 = GameUI.breakLines(var6, Menu.SMALL_FONT, new int[]{var4 - 6 - 20}); + var5 += 13 * var7 + Menu.SMALL_FONT.descent; + } + } + } + + if ((1 & var1.anchor) == 0) { + var2 += 3; + } else { + var2 = 637 - var2; + } + + if ((var1.anchor & 2) == 0) { + var3 += 55; + } else { + var3 = 477 - var3; + } + + if ((2 & var1.anchor) != 0) { + var3 -= var5; + } + + if ((var1.anchor & 1) != 0) { + var2 -= var4; + } + + _jbd = var4 + var2; + _tpb = var3 + var5; + _oia = var3; + _feB = var2; + a195qj(var1); + if (var1.body.contains("<%tabresizehint>")) { + templateDictionary.put("tabresizehint", ""); + } + + if (_olg == null) { + _dmgq = _tpb; + _beh = _oia; + _jcr = _kpj = _jbd + _feB >> 1; + } + + } + } + } + + private static void a195qj(final TutorialMessage var0) { + _tec = 0; + if (var0 == null) { + _spm = null; + _ehL = null; + _oii = null; + _rgf = null; + } else { + final int var2 = Menu.SMALL_FONT.ascent + Menu.SMALL_FONT.descent; + final int var3 = var0._j - 6 - 20; + String var4 = templateDictionary.expand(var0.body); + String[] var5 = GameUI.breakLinesWithColorTags(Menu.SMALL_FONT, var4, new int[]{var3}); + assert var5 != null; + int var6 = var5.length; + Drawing.saveContext(); + int var7; + if (var6 > 0) { + _ehL = new Sprite[var6]; + _ehL[0] = new Sprite(var3, var2); + _ehL[0].installForDrawing(); + Menu.SMALL_FONT.draw(var5[0], 0, Menu.SMALL_FONT.ascent, Drawing.WHITE); + + for (var7 = 1; var7 < var6; ++var7) { + _ehL[var7] = new Sprite(var3, var2); + _ehL[var7].installForDrawing(); + Menu.SMALL_FONT.draw(var5[var7], 0, Menu.SMALL_FONT.ascent, Drawing.WHITE); + } + } else { + _ehL = null; + } + + if (var0.objectives == null) { + _rgf = null; + _oii = null; + _spm = null; + } else { + var7 = var0.objectives.length; + _rgf = new int[var7]; + _spm = new Sprite[var7][]; + _oii = new Sprite[var7][]; + + for (int var8 = 0; var7 > var8; ++var8) { + final TutorialObjective var9 = var0.objectives[var8]; + var4 = templateDictionary.expand(var9.description); + var5 = GameUI.breakLinesWithColorTags(Menu.SMALL_FONT, var4, new int[]{var3}); + assert var5 != null; + var6 = var5.length; + _oii[var8] = new Sprite[var6]; + _spm[var8] = new Sprite[var6]; + + for (int var10 = 0; var10 < var6; ++var10) { + _oii[var8][var10] = new Sprite(var3, var2); + _oii[var8][var10].installForDrawing(); + Menu.SMALL_FONT.draw(var5[var10], 0, Menu.SMALL_FONT.ascent, Drawing.WHITE); + _spm[var8][var10] = _oii[var8][var10].copy(); + _spm[var8][var10].installForDrawing(); + Drawing.b669(1, 1, var3, var2); + } + } + } + + Drawing.restoreContext(); + } + } + + private static void a529ac(final TutorialMessage var1) { + if (_hmq != null) { + final TutorialMessage var2 = !_hmq.noStack ? _hmq : _hmq.next; + if (var2 != null) { + _jsb[_gei++] = var2; + } + } + + a529lp(var1); + } + + private static void b900(final String var0) { + int var5; + if (a517qj("stage", var0)) { + var5 = Integer.parseInt(var0.substring(6)); + a093no(var5); + session.recalculateSystemState(); + } else if (var0.equalsIgnoreCase("zoomtohome")) { + session.gameView.a021(39, _hod.combinedForce.getCapital(), 200.0F); + } else if (var0.equalsIgnoreCase("closetohome")) { + session.gameView.a815(_hod.combinedForce.getCapital()); + } else { + final StarSystem[] var2; + int var3; + StarSystem var4; + if (var0.equalsIgnoreCase("zoomtowarning")) { + var2 = session.gameState.map.systems; + + for (var3 = 0; var2.length > var3; ++var3) { + var4 = var2[var3]; + if (var4.owner == _hod && !session.systemsWillOwn[var4.index]) { + session.gameView.a021(92, var4, 300.0F); + return; + } + } + + } else if (var0.equalsIgnoreCase("zoomOut")) { + session.gameView.c487(); + } else { + if (var0.equalsIgnoreCase("zoom12")) { + session.gameView.a815(session.gameState.map.systems[12]); + } + + if (var0.equalsIgnoreCase("zoomDerelict")) { + var2 = session.gameState.map.systems; + + for (var3 = 0; var2.length > var3; ++var3) { + var4 = var2[var3]; + if (var4.type >= 6) { + session.gameView.a815(var4); + break; + } + } + } + + if (var0.equalsIgnoreCase("block")) { + _isb = true; + } else if (var0.equalsIgnoreCase("capture1")) { + assert false; + } else if (!var0.equalsIgnoreCase("showtabs")) { + if (var0.equalsIgnoreCase("startai")) { + for (var5 = 1; var5 < session.ais.length; ++var5) { + session.ais[var5].initialize(true); + } + + } else { + String var6; + if (a517qj("enable", var0)) { + var6 = var0.substring(7).trim(); + if (var6.endsWith("Button")) { + session.ui.a950(var6, true); + } + + if (var6.equalsIgnoreCase("animationControls")) { + session.ui._K.visible = true; + session.ui.animationAutoPlayButton.activate(); + } + + } else { + if (a517qj("disable", var0)) { + var6 = var0.substring(8).trim(); + if (var6.endsWith("Button")) { + session.ui.a950(var6, false); + } + } + + if (a517qj("hide", var0)) { + var6 = var0.substring(4).trim(); + session.ui.a223(var6, false); + } else if (a517qj("show", var0)) { + var6 = var0.substring(4).trim(); + session.ui.a223(var6, true); + } else if (a517qj("highlight", var0)) { + var6 = var0.substring(10).trim(); + if (var6.equalsIgnoreCase("wormholes")) { + _erg = true; + return; + } + + if (var6.equalsIgnoreCase("borders")) { + _jau = true; + return; + } + + if (var6.equalsIgnoreCase("garrison")) { + _vcj = true; + return; + } + + if (var6.equalsIgnoreCase("resources")) { + _tdL = true; + return; + } + + if (var6.equalsIgnoreCase("productionHammer")) { + _sek = true; + return; + } + + if (var6.equalsIgnoreCase("ready")) { + _phg = true; + } + } + } + } + } + } + } + } + + public static void tick() { + if (_hmq != _olg) { + if (++_ejm >= 32) { + a423js(); + } + } else if (_olg != null) { + _tec += 16; + final TutorialObjective[] var0 = _olg.objectives; + if (var0 != null) { + for (int var1 = 0; var0.length > var1; ++var1) { + if (_rgf[var1] == 0 && a623sp(var0[var1].key)) { + _rgf[var1] = 1; + a154vn(); + } + } + } + } + + if (!a988sr("unplaced")) { + if (a988sr("losegame")) { + a529ac(TutorialMessages.get("lose")); + } + } else if (a896qc("unplaced")) { + a529ac(TutorialMessages.get("unplaced")); + } + + _aja.clear(); + if (_olg == _hmq) { + _eie = _kpj; + _ef = _jcr; + _fkk = _beh; + _klo = _dmgq; + } else { + _ef = MathUtil.ease(_ejm, 32, _jcr, _feB); + _fkk = MathUtil.ease(_ejm, 32, _beh, _oia); + _eie = MathUtil.ease(_ejm, 32, _kpj, _jbd); + _klo = MathUtil.ease(_ejm, 32, _dmgq, _tpb); + } + + if (_oii != null) { + boolean var3 = true; + + for (int var1 = 0; var1 < _rgf.length; ++var1) { + if (_rgf[var1] > 0) { + _rgf[var1]++; + } + + if (_rgf[var1] < 48) { + var3 = false; + } + } + + if (var3) { + TutorialMessage var4 = _olg.next; + if (var4 == null && _gei > 0) { + var4 = _jsb[--_gei]; + } + + if (_isb) { + _isb = false; + final TutorialMessage var2 = _jsb[_gei]; + if (var2 == null || var2 == _olg) { + a529lp(var4); + } else { + a529lp(var2); + } + } else { + a529lp(var4); + } + } + } + } + + private static boolean a517qj(final CharSequence var0, final CharSequence var1) { + final int var2 = var1.length(); + final int var3 = var0.length(); + if (var3 > var2) { + return false; + } else { + for (int var4 = 0; var4 < var3; ++var4) { + final char var5 = var1.charAt(var4); + final char var6 = var0.charAt(var4); + if (var6 != var5 && Character.toLowerCase(var5) != Character.toLowerCase(var6) && Character.toUpperCase(var5) != Character.toUpperCase(var6)) { + return false; + } + } + + return true; + } + } + + private static boolean a896qc(final String var0) { + for (final TutorialMessageId var1 : _qih) { + if (var0.equalsIgnoreCase(var1.key)) { + return false; + } + } + + _qih.add(new TutorialMessageId(var0)); + return true; + } + + private static void a423js() { + _beh = _oia; + _kpj = _jbd; + _phg = false; + _erg = false; + _dmgq = _tpb; + _olg = _hmq; + _jcr = _feB; + _vcj = false; + _tdL = false; + _sek = false; + _jau = false; + _ejm = 0; + if (_olg._m != null) { + final String[] var1 = _olg._m; + + for (final String var3 : var1) { + b900(var3); + } + } + + if (_olg.clearStack) { + _gei = 0; + } + + } + + private static boolean a623sp(final String var0) { + if (var0.equalsIgnoreCase("openProduction")) { + return session.ui.isProductionWindowOpen(); + } else if (var0.equalsIgnoreCase("placeAllFleets")) { + return _hod.combinedForce.fleetsAvailableToBuild == 0; + } else if (var0.equalsIgnoreCase("homeworldEmpty")) { + return _hod.combinedForce.getCapital().remainingGarrison == 0; + } else if (var0.equalsIgnoreCase("homeworldOne")) { + return _hod.combinedForce.getCapital().remainingGarrison == 1; + } else { + final StarSystem[] var2; + int var3; + StarSystem var4; + if (var0.equalsIgnoreCase("captureAll")) { + var2 = session.gameState.map.systems; + + for (var3 = 0; var2.length > var3; ++var3) { + var4 = var2[var3]; + if (_hod != var4.owner) { + return false; + } + } + + return true; + } else if (var0.equalsIgnoreCase("terraforming")) { + var2 = session.gameState.map.systems; + + for (var3 = 0; var2.length > var3; ++var3) { + var4 = var2[var3]; + if (var4.score == StarSystem.Score.TERRAFORMED) { + return true; + } + } + + return false; + } else if (var0.equalsIgnoreCase("placeTannhauser")) { + return session.gameState.projectOrders.stream() + .anyMatch(var6 -> var6.type == GameState.ResourceType.EXOTICS && session.gameState.map.systems[12] == var6.source); + } else if (var0.equalsIgnoreCase("fleetmove")) { + return session.gameState.moveOrders.stream().anyMatch(var5 -> _hod == var5.player); + } else { + return a988sr(var0); + } + } + } + + private static void a093no(final int var0) { + if (stage < var0) { + final Map var2; + try { + stage = var0; + var2 = mapGenerator.a572(stage, true); + } catch (final MapGenerationFailure var13) { + throw new RuntimeException("Failed to advance Tutorial to stage " + stage + ". "); + } + + final StarSystem[] var3 = session.gameState.map.systems; + + for (int var4 = 0; var4 < var3.length; ++var4) { + final StarSystem var5 = var3[var4]; + final StarSystem var6 = var2.systems[var4]; + var6.hasDefensiveNet = var5.hasDefensiveNet; + var6.resources = var5.resources; + var6.garrison = var5.garrison; + var6.remainingGarrison = var5.remainingGarrison; + var6.score = var5.score; + + final int var7 = (int) Arrays.stream(var5.neighbors).filter(var10 -> !var6.hasNeighbor(var10)).count(); + + if (var7 > 0) { + final StarSystem[] ln_s = new StarSystem[var6.neighbors.length + var7]; + int i = 0; + + int var9; + for (var9 = 0; var9 < var6.neighbors.length; ++var9) { + ln_s[var9] = var6.neighbors[var9]; + } + + for (final StarSystem var12 : var5.neighbors) { + if (!var6.hasNeighbor(var12)) { + ln_s[i + var9] = var2.systems[var12.index]; + ++i; + } + } + + var6.neighbors = ln_s; + } + + var6.lastOwner = var5.lastOwner; + var6.owner = var5.owner; + var6.contiguousForce = var5.contiguousForce; + if (var5.owner != null) { + assert var6.contiguousForce != null; + + var6.contiguousForce.add(var6); + if (var5 == var5.contiguousForce.getCapital()) { + var6.contiguousForce.setCapital(var6); + } + + var6.owner.combinedForce.add(var6); + if (var5 == var5.owner.combinedForce.getCapital()) { + var6.owner.combinedForce.setCapital(var6); + } + + var5.contiguousForce.remove(var5); + var5.owner.combinedForce.remove(var5); + } + } + + session.setMap(var2); + if (_idd != null) { + _idd = var2.systems[_idd.index]; + } + + if (_dd != null) { + _dd = var2.systems[_dd.index]; + } + + final StarSystem[] var14 = var2.systems; + + for (final StarSystem ln_ : var14) { + templateDictionary.put("star" + ln_.index, a865pa(ln_, -31)); + } + + Player var15 = null; + if (stage == 5) { + var15 = new Player(1, StringConstants.EMPIRE_NAMES[1], GameUI.PLAYER_COLORS_DARK[1], GameUI.PLAYER_COLORS_1[1], GameUI.PLAYER_COLORS_2[1]); + var2.systems[6].lastOwner = var15; + var2.systems[6].owner = var15; + var2.systems[7].lastOwner = var15; + var2.systems[7].owner = var15; + var15.combinedForce = new CombinedForce(var15, var2.systems[7]); + var15.combinedForce.add(var2.systems[7]); + var15.combinedForce.add(var2.systems[6]); + final ContiguousForce var17 = new ContiguousForce(var15, var2.systems[7]); + var17.add(var2.systems[7]); + var17.add(var2.systems[6]); + var2.systems[6].contiguousForce = var17; + var2.systems[7].contiguousForce = var17; + var15.contiguousForces.add(var17); + var15.stats = new PlayerStats(var2.systems[7].garrison + var2.systems[6].garrison); + } + + if (stage == 6) { + var15 = new Player(2, StringConstants.EMPIRE_NAMES[2], GameUI.PLAYER_COLORS_DARK[2], GameUI.PLAYER_COLORS_1[2], GameUI.PLAYER_COLORS_2[2]); + final StarSystem var5 = var2.systems[17]; + var5.owner = var15; + var5.lastOwner = var15; + var15.combinedForce = new CombinedForce(var15, var5); + var15.combinedForce.add(var5); + final ContiguousForce var18 = new ContiguousForce(var15, var5); + var18.add(var5); + var5.contiguousForce = var18; + var15.contiguousForces.add(var18); + var15.stats = new PlayerStats(var5.garrison); + } + + if (stage == 7) { + var15 = new Player(3, StringConstants.EMPIRE_NAMES[3], GameUI.PLAYER_COLORS_DARK[3], GameUI.PLAYER_COLORS_1[3], GameUI.PLAYER_COLORS_2[3]); + final StarSystem var5 = var2.systems[37]; + final StarSystem var6 = var2.systems[36]; + final StarSystem var19 = var2.systems[35]; + final StarSystem var21 = var2.systems[34]; + var5.lastOwner = var15; + var5.owner = var15; + final StarSystem var25 = var2.systems[33]; + var6.lastOwner = var15; + var6.owner = var15; + var19.lastOwner = var15; + var19.owner = var15; + var21.owner = var15; + var21.lastOwner = var15; + var25.lastOwner = var15; + var25.owner = var15; + var15.combinedForce = new CombinedForce(var15, var5); + var15.combinedForce.add(var5); + var15.combinedForce.add(var6); + var15.combinedForce.add(var19); + var15.combinedForce.add(var21); + var15.combinedForce.add(var25); + final ContiguousForce var24 = new ContiguousForce(var15, var5); + var24.add(var5); + var24.add(var6); + var24.add(var19); + var24.add(var21); + var24.add(var25); + var5.contiguousForce = var24; + var6.contiguousForce = var24; + var19.contiguousForce = var24; + var21.contiguousForce = var24; + var25.contiguousForce = var24; + var15.contiguousForces.add(var24); + var15.stats = new PlayerStats(var21.garrison + var19.garrison + var6.garrison + var5.garrison + var25.garrison); + } + + if (var15 != null) { + session.addTutorialAIPlayer(var15); + session.gameView.a073(session.gameState.players); + session.ui.a735(session.gameState.players); + templateDictionary.put("player" + var15.index, Strings.format(">" + var15.name + "", Integer.toString(var15.color2, 16))); + } + + a195qj(_olg); + } + } + + private static String a865pa(final StarSystem var0, final int var1) { + final int var2 = var0.owner == null ? 8421504 : var0.owner.color2; + if (var1 > -3) { + StringConstants.FS_BUTTON_ACCEPT = null; + } + + return Strings.format(">" + var0.name + "", Integer.toString(var2, 16)); + } + + private static boolean a988sr(final String var1) { + return _aja.stream().anyMatch(var2 -> var1.equalsIgnoreCase(var2.key)) + || _qih.stream().anyMatch(var2 -> var1.equalsIgnoreCase(var2.key)); + } + + private static boolean a154vn() { + int var0 = _ehL != null ? _ehL.length : 0; + int var1; + if (_oii != null) { + for (var1 = 0; _oii.length > var1; ++var1) { + var0 += _oii[var1].length; + } + } + + var1 = var0 * _olg._j; + if (var1 <= _tec) { + return true; + } else { + _tec = var1; + return false; + } + } + + public static void k150pe() { + a984fl("endturn"); + if (session.gameState.map.systems.length == 2) { + if (_hod == session.gameState.map.systems[1].owner) { + if (a896qc("combatSuccess")) { + a529ac(TutorialMessages.get("combatSuccess")); + } + } else { + final CombatEngagementLog var0 = a471tl(session.gameState.map.systems[1]); + if (var0 != null && a896qc("combatFailed")) { + a529ac(TutorialMessages.get("combatFailed")); + } + } + + final CombatEngagementLog var0 = a471tl(session.gameState.map.systems[1]); + if (var0 != null) { + templateDictionary.put("combatreport1", a495cm(var0)); + } + + templateDictionary.put("garrison1", Integer.toString(session.gameState.map.systems[1].garrison)); + } + + if (session.gameState.hasEnded && session.gameState.winnerIndex != _hod.index) { + a529ac(TutorialMessages.get("lose")); + } + + final StarSystem[] var4 = session.gameState.map.systems; + + for (final StarSystem var2 : var4) { + final int var3 = var2.owner != null ? var2.owner.color2 : 8421504; + templateDictionary.put("star" + var2.index, Strings.format(">" + var2.name + "", Integer.toString(var3, 16))); + } + } + + private static CombatEngagementLog a471tl(final StarSystem var1) { + if (session.turnEventLog != null) { + for (final TurnEventLog.Event var2 : session.turnEventLog.events) { + if (var2 instanceof CombatEngagementLog var3) { + if (var1 == var3.system) { + final Player[] var4 = var3.players; + + for (final Player var6 : var4) { + if (var6 == _hod) { + return var3; + } + } + + return null; + } + } + } + + } + return null; + } + + private static String a495cm(final CombatEngagementLog var0) { + int var1 = 0; + int var2 = 0; + + for (final CombatLogEvent var3 : var0.events) { + if (_hod == var3.player) { + if (var3.fleetsRetreated != 0 && var3.source != null) { + ++var2; + } + + var1 += var3.fleetsDestroyed; + } + } + + if (var1 == 0) { + return StringConstants.TUTORIAL_LOST_NONE; + } else { + String var4 = var1 != 1 ? Strings.format(StringConstants.TUTORIAL_LOST_MULTIPLE, Integer.toString(var1)) : StringConstants.TUTORIAL_LOST_SINGLE; + if (var2 != 0) { + final String[] var5 = new String[1 + var2]; + int i = 1; + var5[0] = var4; + + for (final CombatLogEvent var3 : var0.events) { + if (var3.player == _hod && var3.fleetsRetreated != 0 && var3.source != null) { + final String var6; + if (var3.fleetsRetreated == 1) { + var6 = Strings.format(StringConstants.FLEET_HAS_RETREATED_TO, a865pa(var3.source, -110)); + } else { + var6 = Strings.format(StringConstants.TUTORIAL_RETREATING_MULTIPLE, a865pa(var3.source, -97), Integer.toString(var3.fleetsRetreated)); + } + + var5[i++] = var6; + } + } + + var4 = a399va(var5); + } + + return var4; + } + } + + private static String a399va(final String[] var1) { + if (var1 == null || var1.length == 0) { + return null; + } else if (var1.length == 1) { + return var1[0]; + } else { + final int var2 = var1.length - 2; + final StringBuilder var3 = new StringBuilder(20); + + for (int var4 = 0; var2 > var4; ++var4) { + var3.append(var1[var4]); + var3.append(StringConstants.TEXT_JOIN); + } + + var3.append(var1[var2]); + var3.append(StringConstants.TEXT_JOIN_FINAL); + var3.append(var1[1 + var2]); + return var3.toString(); + } + } + + public static void a423mq() { + if (_olg != null || _hmq != null) { + if (-_ef + _eie > 20 && -_fkk + _klo > 20) { + Menu.drawShine(_ef, _fkk, -_ef + _eie, -_fkk + _klo, Drawing.alphaOver(0, 3974311, 128), true); + } + + if (_olg == _hmq) { + final int var1 = _ef + 13; + int var2 = 6 + _fkk; + int var3 = _tec; + int var4; + if (_ehL != null) { + if (_tec <= 0) { + return; + } + + a833sa(_tec, var1, 16, _ehL[0], var2); + + for (var4 = 1; _ehL.length > var4; ++var4) { + var3 -= _olg._j; + if (var3 <= 0) { + return; + } + + var2 += 13; + a833sa(var3, var1, 16, _ehL[var4], var2); + } + + var2 += 13; + } + + if (_oii != null) { + for (var4 = 0; _oii.length > var4; ++var4) { + final Sprite[] var5 = _oii[var4]; + int var6 = _rgf[var4]; + if (var6 <= 0) { + for (final Sprite bi_ : var5) { + var3 -= _olg._j; + if (var3 <= 0) { + return; + } + + var2 += 13; + a833sa(var3, var1, 16, bi_, var2); + } + } else { + final Sprite[] var7 = _spm[var4]; + int var8; + if (var6 > 32) { + var6 = -var6 + 48; + if (var6 >= 0) { + var6 = (var6 << 8) / 16; + } else { + var6 = 0; + } + + for (var8 = 0; var5.length > var8; ++var8) { + var3 -= _olg._j; + var2 += 13; + var5[var8].drawAdd(var1, var2, var6); + var7[var8].drawAdd(var1, var2, var6); + } + } else { + var6 = (var6 << 8) / 32; + + for (var8 = 0; var5.length > var8; ++var8) { + var2 += 13; + var3 -= _olg._j; + var5[var8].drawAdd(var1, var2, 256); + var7[var8].drawAdd(var1, var2, var6); + } + } + + if (var3 < 0) { + _tec -= var3; + var3 = 0; + } + } + + var2 += 13; + } + } + } + } + } + + public static void a833sa(final int var0, final int var1, final int var2, final Sprite var3, final int var4) { + final int var5 = Drawing.top; + final int var6 = Drawing.bottom; + final int var7 = Drawing.left; + final int var8 = Drawing.right; + if (var0 >= var2) { + Drawing.expandBoundsToInclude(var1, var5, -var2 + var1 + var0, var6); + var3.drawAdd(var1, var4, 256); + } + + final int var9 = var8 - var7 - 1; + int var10 = var0 >= var2 ? var0 - var2 : 0; + int var11 = var0; + if (var10 < -var1 + var7) { + var10 = var7 - var1; + } + + if (var9 < var0) { + var11 = var9; + } + + for (int var12 = var10; var12 < var11; ++var12) { + final int var13 = (var0 - var12 << 8) / var2; + Drawing.setBounds(var12 + var1, var5, var12 + var1 + 1, var6); + var3.drawAdd(var1, var4, var13); + } + + Drawing.setBounds(var7, var5, var8, var6); + } + + public static boolean a881ks(final boolean var0) { + if ((_olg != null || _hmq != null) && JagexApplet.mouseX >= _ef && JagexApplet.mouseX < _eie && _fkk <= JagexApplet.mouseY && _klo > JagexApplet.mouseY) { + if (JagexApplet.mouseButtonJustClicked != MouseState.Button.NONE && var0) { + if (_olg != _hmq) { + a423js(); + } + + if (a154vn()) { + a984fl("enter"); + } + } + + return true; + } else { + return false; + } + } + + public static Rect b520b() { + final Rect var2 = new Rect(0, 50, ShatteredPlansClient.SCREEN_WIDTH, 430); + final Rect var4 = new Rect(_ef, _fkk, _eie, _klo); + final List var5 = new ArrayList<>(); + if (var2.x1 < var4.x1) { + var5.add(new Rect(var2.x1, var2.y1, Math.min(var4.x1, var2.x2), var2.y2)); + } + + if (var4.x2 < var2.x2) { + var5.add(new Rect(Math.max(var4.x2, var2.x1), var2.y1, var2.x2, var2.y2)); + } + + if (var4.y1 > var2.y1) { + var5.add(new Rect(var2.x1, var2.y1, var2.x2, Math.min(var2.y2, var4.y1))); + } + + if (var2.y2 > var4.y2) { + var5.add(new Rect(var2.x1, Math.max(var2.y1, var4.y2), var2.x2, var2.y2)); + } + + int var6 = 0; + Rect var7 = null; + + for (final Rect var8 : var5) { + final int var9 = -var8.x1 + var8.x2; + final int var10 = -var8.y1 + var8.y2; + final int var11 = var10 * var9 * (Math.min(var9, var10)); + if (var11 > var6) { + var7 = var8; + var6 = var11; + } + } + + return var7; + } + + @SuppressWarnings("StringConcatenationInLoop") + private static void a150sj() { + final Player var1 = _hod; + final CombinedForce var2 = var1.combinedForce; + + if (var2 != null) { + final int var4 = var2.surplusResources[var2.surplusResourceRanks[3]]; + if (var4 == 0) { + templateDictionary.put("generateshortfall", StringConstants.TUTORIAL_BALANCED); + } else { + String neededResources = null; + int neededResourcesSoFar = 0; + + for (int i = 0; i < GameState.NUM_RESOURCES; ++i) { + final int resource = var2.surplusResourceRanks[i]; + if (var2.surplusResources[resource] == 0) { + final String resourceName = Strings.format("><%1>", Integer.toString(GameView.RESOURCE_COLORS[resource], 16), StringConstants.RESOURCE_NAMES[resource]); + if (neededResourcesSoFar == 0) { + neededResources = resourceName; + } else if (neededResourcesSoFar == 1) { + neededResources = resourceName + StringConstants.TEXT_JOIN_FINAL + neededResources; + } else { + neededResources = resourceName + StringConstants.TEXT_JOIN + neededResources; + } + + ++neededResourcesSoFar; + } + } + + String var11 = Strings.format(StringConstants.TUTORIAL_SHORTFALL1, neededResources); + if (neededResourcesSoFar == 1) { + var11 = var11 + StringConstants.TUTORIAL_SHORTFALL2A; + } else { + var11 = var11 + StringConstants.TUTORIAL_SHORTFALL_2B; + } + + templateDictionary.put("generateshortfall", var11); + } + } + + templateDictionary.put("generateprojectprogress", null); + } + + public static void a018jr(final String var0, final String var2) { + templateDictionary.put(var0, var2); + } + + public static void a984fl(final String var0) { + _aja.add(new TutorialMessageId(var0)); + } + + static GameState createTutorialGameState(final int turnLengthIndex, final GameOptions options, final String[] playerNames) { + final GameState var4 = new GameState(turnLengthIndex, options, GameState.GameType.TUTORIAL, playerNames); + + final TutorialMapGenerator var5 = new TutorialMapGenerator(); + var4.map = var5.generate(); + var4.map.assignPlayerHomeworlds(var4.players, options); + var4.recalculateFleetProduction(); + var4.recalculatePlayerFleetProduction(); + return var4; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/intro/IntroAnimation.java b/src/main/java/funorb/shatteredplans/client/intro/IntroAnimation.java new file mode 100644 index 0000000..517be16 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/intro/IntroAnimation.java @@ -0,0 +1,1248 @@ +package funorb.shatteredplans.client.intro; + +import funorb.awt.KeyState; +import funorb.awt.MouseState; +import funorb.cache.ResourceLoader; +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.graphics.Sprite; +import funorb.graphics.SpriteResource; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.client.JagexApplet; +import funorb.shatteredplans.client.Menu; +import funorb.shatteredplans.client.ShatteredPlansClient; +import funorb.shatteredplans.client.Sounds; +import funorb.util.MathUtil; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public final class IntroAnimation { + private static final int[] _fex = new int[256]; + private static final int[] _feu = new int[256]; + private static final nd_[] _fey; + private static final nd_[] _feH; + private static final nd_[] _feC; + private static List _rpK; + private static boolean resourcesLoaded; + public static int _ucv = 0; + private static boolean _cio; + private static Sprite[] TEXT_INTRO_0; + private static Sprite _heh; + private static Sprite INTRO_3_CITY_FG; + private static Sprite INTRO_3_CRATER; + private static Sprite _qqn; + private static float _cfe; + private static Sprite _wef; + private static Sprite INTRO_3_CITY_BG; + private static Sprite _ksj; + private static Sprite _tfb; + private static List _cbh; + private static int _dpr; + private static int[] _pA; + private static int _cfp; + public static ResourceLoader spriteLoader; + private static Sprite INTRO_1_3; + private static Sprite INTRO_1_GLOW; + private static Sprite INTRO_1_GLOW_FG; + private static Sprite _mcu; + private static Sprite _dsb; + private static Sprite _mar; + private static Sprite INTRO_2_CLOUDS; + private static boolean _pn; + private static int[] _npf; + private static int _dim; + private static boolean resourcesInitialized; + private static Font currentFont; + private static Sprite INTRO_1_2; + private static Sprite INTRO_1_1; + private static Sprite INTRO_1_FLASH; + private static Sprite INTRO_3_STARS; + private static Sprite INTRO_2_EARTH; + private static int _ua; + private static int currentStage; + private static int nextStage; + private static int timeTillNextStage; + + static { + final int[] var2 = new int[]{327, 239, 128, 326, 639, 717, 529, 507, 132, 195, 772, 777, 211, 319, 84, 202, 717, 303, 235, 193}; + final int[] var3 = new int[]{395, 478, 553, 617, 475, 615, 611, 384, 552, 628, 492, 403, 401, 348, 627, 393, 615, 509, 500, 545}; + _feC = new nd_[var2.length]; + for (int var4 = 0; var4 < var2.length; ++var4) { + _feC[var4] = new nd_(var2[var4], var3[var4], 240); + } + + for (int var0 = 0; var0 < 256; ++var0) { + _feu[var0] = 65793 * var0; + _fex[var0] = var0 >> 1 << 8 | var0 | var0 >> 2 << 16; + } + + final int[] var5 = new int[]{256, 251, 245, 239, 219, 215, 161, 157, 154, 150, 146, 144, 316, 306, 612, 604, 599, 774, 777}; + final int[] var1 = new int[]{199, 209, 223, 235, 214, 227, 289, 302, 313, 327, 338, 351, 247, 267, 180, 209, 240, 235, 258}; + _fey = new nd_[12]; + + int var4; + for (var4 = 0; var4 < 12; ++var4) { + _fey[var4] = new nd_(var5[var4], var1[var4], 80); + } + + _feH = new nd_[7]; + + for (var4 = 0; var4 < 7; ++var4) { + _feH[var4] = new nd_(var5[var4 + 12], var1[var4 + 12], 144); + } + } + + public static void reset() { + _ua = ShatteredPlansClient.randomIntBounded(50); + currentFont = Menu.SMALL_FONT; + _rpK = new ArrayList<>(); + currentStage = 0; + nextStage = 0; + _dim = 0; + _pn = false; + timeTillNextStage = 0; + ShatteredPlansClient.a827jo(null, 50, true); + if (_cbh != null) { + _cbh.clear(); + } + } + + public static void tick() { + if (resourcesLoaded) { + if (!resourcesInitialized) { + initializeResources(); + } + } else if (spriteLoader.loadGroupData("intro")) { + resourcesLoaded = true; + } + + while (JagexApplet.nextTypedKey()) { + if (JagexApplet.lastTypedKeyCode == KeyState.Code.ESCAPE) { + a366jc(-1); + } else if (JagexApplet.lastTypedKeyCode == KeyState.Code.SPACE && !_pn && resourcesInitialized && timeTillNextStage > 0) { + a150ph(); + a366jc(currentStage < 5 ? currentStage + 1 : -1); + } + } + + if (_ua + 50 < ShatteredPlansClient.currentTick) { + _ua = ShatteredPlansClient.currentTick + ShatteredPlansClient.randomIntBounded(50); + } + + final int var1 = ShatteredPlansClient.currentTick - _ua; + if (var1 < 0) { + _dpr = 0; + } else if (var1 < 10) { + _dpr = var1 * 25; + } else if (var1 < 15) { + _dpr = 500 - 25 * var1; + } else if (var1 < 20) { + _dpr = 25 * var1 - 150; + } else if (var1 < 25) { + _dpr = 750 - var1 * 25; + } else if (var1 < 30) { + _dpr = 25 * var1 - 400; + } else if (var1 >= 40) { + _dpr = 0; + } else { + _dpr = 1000 - var1 * 25; + } + + if (_pn) { + if (--timeTillNextStage <= 0) { + _pn = false; + currentStage = nextStage; + timeTillNextStage = 0; + if (currentStage == -1) { + _ucv = 50; + Menu.switchTo(Menu.Id.MAIN, 0, false); + ShatteredPlansClient.switchMenus(); + freeResources(); + } + + if (currentStage == 2) { + b150gq(); + } + + if (currentStage == 4) { + _pA = new int[600]; + _cfp = 0; + + _npf = new int[600]; + } + + _dim = 0; + } + } else if (timeTillNextStage < 50) { + ++timeTillNextStage; + } + + b150ej(); + switch (currentStage) { + case 0 -> tickStage0(); + case 1 -> tickStage1(); + case 2 -> tickStage2(); + case 3 -> tickStage3(); + case 4 -> tickStage4(); + case 5 -> tickStage5(); + } + + _cio = JagexApplet.mouseX >= 540 && JagexApplet.mouseX < 620 && JagexApplet.mouseY >= 440 && JagexApplet.mouseY < 460; + + if (JagexApplet.mouseButtonJustClicked != MouseState.Button.NONE) { + if (JagexApplet.mousePressX >= 540 && JagexApplet.mousePressX < 620 && JagexApplet.mousePressY >= 440 && JagexApplet.mousePressY < 460) { + a366jc(-1); + } else if (!_pn && resourcesInitialized && timeTillNextStage > 0) { + a150ph(); + a366jc(currentStage >= 5 ? -1 : 1 + currentStage); + } + } + } + + public static void render() { + switch (currentStage) { + case 0 -> renderStage0(); + case 1 -> renderStage1(); + case 2 -> renderStage2(); + case 3 -> renderStage3(); + case 4 -> renderStage4(); + case 5 -> renderStage5(); + } + + if (timeTillNextStage < 50) { + if (currentStage == (_pn ? 2 : 3) || _pn && nextStage == -1) { + a669(255 - (5 * timeTillNextStage)); + } else { + a455cle(Drawing.width, 256, 5 * timeTillNextStage, Drawing.height); + } + } + + a423qn(); + int var1 = currentFont.measureLineWidth(StringConstants.TEXT_SKIP_INTRO) + 20; + if (var1 < 80) { + var1 = 80; + } + + a544pvc(var1, currentFont, -20 - var1 + ShatteredPlansClient.SCREEN_WIDTH, StringConstants.TEXT_SKIP_INTRO, _cio); + } + + private static void a455cle(int var1, final int var3, final int var4, int var5) { + final int var0 = 0; + final int var2 = 0; + + if (var1 + var2 > Drawing.width) { + var1 = Drawing.width - var2; + } + + if (Drawing.height < var5 + var0) { + var5 = Drawing.height; + } + + final int var6 = var3 * var4 >> 8; + final int var7 = -var6 + var4; + final int var8 = var5 + var0; + + for (int var9 = var0; var9 < var8; ++var9) { + int var10 = Drawing.pixelIndex(var2, var9); + + for (int var11 = var1; var11 > 0; --var11) { + final int var12 = Drawing.screenBuffer[var10]; + final int var13 = (16711680 & var12) >> 16; + final int var14 = 255 & var12 >> 8; + final int var15 = 255 & var12; + final int var16 = 5 * var13 + var14 * 6 + 5 * var15; + final int var17 = (var13 * var6 >> 8) + (var16 * var7 >> 12); + final int var18 = (var14 * var6 >> 8) + (var7 * var16 >> 12); + final int var19 = (var15 * var6 >> 8) + (var16 * var7 >> 12); + final int var20 = var19 | var18 << 8 | var17 << 16; + Drawing.screenBuffer[var10] = var20; + ++var10; + } + } + } + + private static void renderStage0() { + if (TEXT_INTRO_0 == null) { + TEXT_INTRO_0 = new Sprite[]{renderStage0Text(StringConstants.TEXT_INTRO_0[0]), renderStage0Text(StringConstants.TEXT_INTRO_0[1])}; + } + + Drawing.clear(); + draw(TEXT_INTRO_0[0], (ShatteredPlansClient.SCREEN_WIDTH - TEXT_INTRO_0[0].width) >> 1, (short) 240, 256, _dim << 1); + draw(TEXT_INTRO_0[1], (ShatteredPlansClient.SCREEN_WIDTH - TEXT_INTRO_0[1].width) >> 1, (short) 240 + TEXT_INTRO_0[1].height, 256, (_dim << 1) - 128); + if (!resourcesLoaded) { + renderLoading(spriteLoader.percentLoaded("intro")); + } + } + + private static void renderStage1() { + Drawing.clear(); + final int var2 = 300 - _dim; + final int var1 = var2 / 8 - 25; + INTRO_1_3.drawTinted2(var1, 0, 33023); + final int i = var2 / 6 - 100; + INTRO_1_2.drawTinted2(i, 0, 4227327); + INTRO_1_GLOW.draw(i, 0, _dpr / 8); + + for (final nd_ var5 : _fey) { + if (var5._a != 0) { + Drawing.drawCircleGradientAdd(i + var5._e << 4, var5._j << 4, var5._f, var5._a, _feu); + } + } + + final int i1 = var2 / 4 - 250; + INTRO_1_1.drawTinted2(i1, 120, 8421631); + INTRO_1_GLOW_FG.draw(i1, 120, _dpr / 4); + INTRO_1_FLASH.draw(i1, 120, _dpr); + + for (final nd_ var5 : _feH) { + if (var5._a != 0) { + Drawing.drawCircleGradientAdd(var5._e + i1 << 4, var5._j + 120 << 4, var5._f, var5._a, _feu); + } + } + } + + private static void renderStage2() { + final float var2 = (float) _dim / 1000.0F + 0.15F; + int var0 = -((int) (200.0D * Math.sin(var2))); + final int var1 = (int) (Math.cos(var2) * 200.0D) - 200; + INTRO_3_STARS.draw(var0, var1); + int var3 = -(_dim * 120 / 1000) + 176; + final int var4 = 540 - var3; + Drawing.saveContext(); + if (var4 < 256) { + var3 = 284; + } + + if (_mcu == null) { + _mcu = _dsb.copy(); + _mcu.installForDrawing(); + } else { + _mcu.installForDrawing(); + _dsb.c093(0, 0); + } + + final byte var9 = -5; + int i = 100 * _dim / 1000 - 80; + ShatteredPlansClient.a034so(0, i - var3 + INTRO_2_EARTH.y, _mar); + Drawing.restoreContext(); + int var5 = 256; + if (_dim < 512) { + var5 = _dim >> 1; + Drawing.fillCircle(320, var3 + 528, 400, Drawing.WHITE); + } + + INTRO_2_EARTH.draw(var9, i); + a885tg(i, INTRO_2_CLOUDS); + _mcu.drawAdd(0, var3, var5 * (_dpr < 0 ? 0 : (Math.min(_dpr, 256))) >> 8); + _mcu.drawAdd(0, var3, var5); + + for (final nd_ var8 : _feC) { + if (var8._a != 0) { + Drawing.drawCircleGradientAdd(var8._e + var9 << 4, var8._j + i << 4, var8._f, var8._a, _feu); + } + } + + for (final sb_ var11 : _rpK) { + i = (int) var11._n; + var0 = (int) var11._l; + + for (int var7 = 1; var7 < 50; ++var7) { + int var12 = -var7 + var11._q; + Drawing.drawCircleGradientAdd(var0 << 4, i << 4, -var7 + 50, -(var7 * 2) + 100, _feu); + if (var12 < 0) { + var12 += 50; + } + + var0 = (int) var11._o[var12]; + i = (int) var11._i[var12]; + } + + Drawing.drawCircleGradientAdd((int) var11._l << 4, (int) var11._n << 4, 128, 100, _feu); + } + + } + + private static void renderStage3() { + final float var2 = (float) _dim / 1000.0F + 0.15F; + final int var0 = -((int) (Math.sin(var2) * 200.0D)); + final int var1 = (int) (Math.cos(var2) * 200.0D) - 200; + INTRO_3_STARS.draw(var0, var1); + final int i = -(_dim * 40 / 800) + 200; + final byte var3 = -62; + _heh.drawAdd(var3, i - 60, 256); + final int i1 = 300 - 150 * _dim / 800; + final byte b = -120; + _wef.drawAdd(b, i1 - 60, 256); + final byte i2 = -62; + final int i3 = -(_dim * 40 / 800) + 200; + INTRO_3_CITY_BG.draw(i2, i3); + final byte i4 = -120; + final int i5 = -(_dim * 150 / 800) + 300; + INTRO_3_CITY_FG.draw(i4, i5); + final int i6 = _dim * 240 / 800 + 20; + final byte var4 = 0; + INTRO_3_CRATER.draw(var4, i6); + Drawing.fillRect(0, INTRO_3_CRATER.offsetY + i6, ShatteredPlansClient.SCREEN_WIDTH, ShatteredPlansClient.SCREEN_HEIGHT, 0); + } + + private static void renderStage4() { + final float var3 = 0.15F + (float) _dim / 1000.0F; + final int var1 = -((int) (200.0D * Math.sin(var3))); + final int var2 = (int) (200.0D * Math.cos(var3)) - 200; + _ksj.draw(var1, var2); + Drawing.h115(0, 0, Drawing.width, Drawing.height); + final byte var4 = 125; + final short var5 = 400; + final int var6 = 550; + final int var7 = 650; + final int var9 = 450; + final byte var10 = -80; + final short var11 = 140; + final short var34 = -260; + final int var12 = _dim >= var5 ? var11 : (_dim >= var4 ? MathUtil.ease(-125 + _dim, 275, var10, var11) : var10); + _tfb.drawAdd(var34, var10 + (var12 - 120), 128); + _qqn.draw(var34, var12 + var10); + final int var13 = _dim < var5 ? (_dim >= var4 ? MathUtil.ease(_dim - var4, 275, 0, 2000) : 0) : 2000; + final int var14 = 3104; + final int var15 = -var13 + (3424); + int var16 = 32 + ShatteredPlansClient.randomIntBounded(32); + if (_dim < var6) { + Drawing.drawCircleGradientAdd(var14, var15, var16, 128, _feu); + } + + int var17 = 197; + int var18 = var17 << 4; + int var19 = (var13 >> 4) - 36; + + int var20 = var19 << 4; + int var21 = 144; + int var22; + int var23; + int var24; + if (_dim >= var7) { + var22 = -650 + _dim; + var23 = 350; + var24 = var22 << 2; + var24 += var22 * 16 * var22 / var23; + var20 -= var24 >> 4; + var21 = var21 * (-var22 + var23) / var23; + var17 += var24 >> 4; + var19 -= var24 >> 8; + var18 += var24; + } + + var22 = 3152; + var23 = 1424; + var24 = 1200; + var24 += 4114; + var22 += var24; + var23 -= var24 >> 4; + Drawing.setBounds(0, 0, var22 + 320 >> 4, ShatteredPlansClient.SCREEN_HEIGHT); + Drawing.fillRect(var17, var19, 20, 4, 0); + int var25; + int var26; + if (_dim >= var9) { + var25 = -450 + _dim; + var26 = 100; + final int var27 = 440 * var25 / var26; + int var28 = var27 + ShatteredPlansClient.randomIntBounded(-64, 64); + if (var28 < 0) { + var28 = 0; + } + + if (var28 > 255) { + var28 = 255; + } + + Drawing.setPixel(16 + var17, var19 + 2, (var28 >> 2) * 65793); + int i = var27 + ShatteredPlansClient.randomIntBounded(-64, 64) - 40; + if (i < 0) { + i = 0; + } + + if (i > 255) { + i = 255; + } + + Drawing.setPixel(3 + var17, var19 + 3, 65793 * (i >> 2)); + int i1 = ShatteredPlansClient.randomIntBounded(-64, 64) + (var27 - 80); + if (i1 < 0) { + i1 = 0; + } + + if (i1 > 255) { + i1 = 255; + } + + Drawing.setPixel(var17 + 12, var19, 65793 * (i1 >> 2)); + int i2 = var27 - 120 + ShatteredPlansClient.randomIntBounded(-64, 64); + if (i2 < 0) { + i2 = 0; + } + + if (i2 > 255) { + i2 = 255; + } + + Drawing.setPixel(var17 + 7, 1 + var19, (i2 >> 2) * 65793); + } + + Drawing.a797(); + if (_dim >= var9) { + var25 = -450 + _dim; + var26 = 250; + final double var35 = 3.141592653589793E-4D * (double) var25 * (double) var25; + final int var29 = var25 <= var26 ? var25 * 128 / var26 : 128; + + int var30; + int var31; + int var32; + for (var30 = 0; var30 < 3; ++var30) { + var31 = (int) (Math.cos(Math.PI * (double) (2 * var30) / 3.0D + var35) * (double) (var21 >> 1)); + var31 += var18; + var32 = (int) ((double) var21 * Math.sin(var35 + Math.PI * (double) (var30 * 2) / 3.0D)); + var32 += var20; + if (var22 + 320 >= var31) { + Drawing.line(var17, var19, var31 >> 4, var32 >> 4, 0); + Drawing.drawCircleGradientAdd(var31, var32, 64, var29, _fex); + _pA[_cfp] = var31; + _npf[_cfp] = var32; + if (++_cfp == 600) { + _cfp = 0; + } + } + } + + var30 = Math.min(600, var25); + var31 = _cfp - 1; + + for (var32 = 0; var30 > var32; ++var32) { + if (var31 < 0) { + var31 += 600; + } + + final int var33 = 256 * (var30 - var32) / 600; + Drawing.drawCircleGradientAdd(_pA[var31], _npf[var31], var33, 12, _fex); + Drawing.drawCircleGradientAdd(_pA[var31], _npf[var31], var33 >> 2, 128, _fex); + --var31; + } + } + + if (_dim > 900) { + if (_dim <= 950) { + var16 = MathUtil.ease(_dim - 950, 50, 256, 0); + } else { + var16 = MathUtil.ease(_dim - 900, 50, 0, 256); + } + + Drawing.a907(var22, var23, var16); + Drawing.a907(var22 + 128, var23 - 16, var16 >> 1); + Drawing.a907(var22 + 256, var23 - 32, var16 >> 2); + } + + var25 = -var22 + var18; + if (var25 > 0) { + int i = var25; + if (var25 > 320) { + var20 -= var25 - 320 >> 2; + var18 += var25 - 320 << 1; + i = -(var25 >> 2) + 320; + } + + Drawing.drawCircleGradientAdd(var18, var20, i, 256, _feu); + } + + } + + private static void renderStage5() { + ShatteredPlansClient.f423fr(); + final int var1 = ShatteredPlansClient.LOGO.offsetX; + final int var2 = ShatteredPlansClient.LOGO.offsetY; + ShatteredPlansClient.LOGO.drawAdd((-var1 + ShatteredPlansClient.SCREEN_WIDTH) / 2, (ShatteredPlansClient.SCREEN_HEIGHT - var2) / 2, 256); + } + + private static void a669(final int var3) { + final int var10 = var3 * 0x010101; + final int width = Math.min(Drawing.width, ShatteredPlansClient.SCREEN_WIDTH); + final int height = Math.min(Drawing.height, ShatteredPlansClient.SCREEN_HEIGHT); + + for (int i = 0; i < height; ++i) { + int n = i * Drawing.width; + for (int j = width; j > 0; --j) { + final int px = Drawing.screenBuffer[n]; + final int var2 = px + var10; + final int rb = (var10 & 0xff00ff) + (px & 0xff00ff); + final int var100 = ((var2 - rb) & 0x10000) + (rb & 0x1000100); + final int var01 = var100 - (var100 >>> 8); + Drawing.screenBuffer[n++] = var01 | (var2 - var100); + } + } + } + + private static void renderLoading(int introPercentLoaded) { + if (introPercentLoaded > 100) { + introPercentLoaded = 100; + } + + Drawing.horizontalLine(18, 455, 101, Drawing.WHITE); + Drawing.setPixel(17, 456, Drawing.WHITE); + Drawing.horizontalLine(18, 456, 99, 0); + Drawing.setPixel(118, 456, Drawing.WHITE); + + { + final int var11 = 0x202020; + final int var12 = 0x101010; + final int var13 = 457; + final int var14 = 16; + final int var15 = introPercentLoaded + 18; + int var16 = var15 + 5; + final int var17 = 118; + if (var16 > var17) { + var16 = var17; + } + + Drawing.setPixel(var14, var13, Drawing.WHITE); + Drawing.setPixel(1 + var14, var13, 0); + Drawing.horizontalLine(2 + var14, var13, var15 - var14 - 2, 0xff0000); + Drawing.horizontalLine(var15, var13, var16 - var15, var12); + Drawing.horizontalLine(var16, var13, var17 - var16, var11); + Drawing.setPixel(var17, var13, Drawing.WHITE); + Drawing.setPixel(117, var13, 0); + } + + for (int var8 = 3; var8 < 7; ++var8) { + final int var9 = (var8 - 2) * 256 / (6); + final int var10 = (0xff00ff00 & (var9 >> 1) * 0xff00ff + (-var9 + 256) * 0xff0000 | 0xff00 * (var9 >> 1) & 16711680) >>> 8; + final int var11 = (0xff0000 & (-var9 + 256) * 8192 + 0xC000 * (var9 >> 1) | 0xff00ff00 & 0x200020 * (256 - var9) + 0xc000c0 * (var9 >> 1)) >>> 8; + final int var12 = (0xfefefe & var11) >> 1; + final int var13 = var8 + 455; + final int var14 = introPercentLoaded + 18; + int var15 = var14 + 5; + final int var16 = 118; + if (var15 > var16) { + var15 = var16; + } + + Drawing.setPixel(15, var13, Drawing.WHITE); + Drawing.setPixel(16, var13, 0); + Drawing.horizontalLine(17, var13, var14 - 15 - 2, var10); + Drawing.horizontalLine(var14, var13, var15 - var14, var12); + Drawing.horizontalLine(var15, var13, -var15 + var16, var11); + Drawing.setPixel(118, var13, Drawing.WHITE); + Drawing.setPixel(117, var13, 0); + } + + { + final int var10 = 0x946969; + final int var11 = 0x747474; + final int var12 = 0x3a3a3a; + final int var13 = 462; + final int var14 = introPercentLoaded + 17; + int var15 = var14 + 5; + final int var16 = 117; + Drawing.setPixel(15, var13, Drawing.WHITE); + if (var15 > var16) { + var15 = var16; + } + + Drawing.setPixel(16, var13, 0); + Drawing.horizontalLine(17, var13, var14 - 17, var10); + Drawing.horizontalLine(var14, var13, -var14 + var15, var12); + Drawing.horizontalLine(var15, var13, -var15 + var16, var11); + Drawing.setPixel(var16, var13, Drawing.WHITE); + Drawing.setPixel(var16 - 1, var13, 0); + } + + Drawing.horizontalLine(15, 464, 101, Drawing.WHITE); + Drawing.setPixel(15, 463, Drawing.WHITE); + Drawing.horizontalLine(16, 463, 99, 0); + Drawing.setPixel(116, 463, Drawing.WHITE); + } + + private static void a423qn() { + if (_cbh != null) { + final byte var2 = 20; + int var1 = (int) _cfe + 20; + + for (final RenderedTextLine var0 : _cbh) { + if (var0._h >= 0) { + if (var0._h >= 230) { + if (var0._h < 250) { + draw(var0._o, 17, var1 - 3, 12 * var0._h - 2760, var0._h << 4); + draw(var0._i, var2, var1, 256, var0._h << 4); + } else { + final int var4 = -(5 * var0._h) + 1500; + draw(var0._o, 17, var1 - 3, var4, var0._h << 4); + draw(var0._i, var2, var1, var4, var0._h << 4); + } + } else { + draw(var0._i, var2, var1, 256, var0._h << 4); + } + } + + var1 += var0._i.height; + } + } + } + + private static void a544pvc(final int var0, final Font var1, final int var5, final String var6, final boolean var7) { + a306cl(var5, var0); + var1.drawCentered(var6, var5 + (var0 >> 1), 440 + (var1.ascent + 20 >> 1), Drawing.WHITE); + if (var7) { + final Sprite var12 = new Sprite(var0, 20); + Drawing.saveContext(); + var12.installForDrawing(); + var1.drawCentered(var6, (var0 >> 1) + 1, 20 + var1.ascent >> 1, Drawing.WHITE); + var1.drawCentered(var6, (var0 >> 1) - 1, var1.ascent + 20 >> 1, Drawing.WHITE); + var1.drawCentered(var6, var0 >> 1, (20 + var1.ascent >> 1) + 1, Drawing.WHITE); + var1.drawCentered(var6, var0 >> 1, -1 + (var1.ascent + 20 >> 1), Drawing.WHITE); + Drawing.restoreContext(); + var12.drawAdd(var5, 440, 64); + } + } + + private static Sprite renderStage0Text(final String text) { + final int var3 = Menu.FONT.measureLineWidth(text); + final int var4 = Menu.FONT.ascent + Menu.FONT.descent; + final Sprite var5 = new Sprite(var3, var4); + Drawing.saveContext(); + var5.installForDrawing(); + Menu.FONT.draw(text, 0, Menu.FONT.ascent, Drawing.WHITE); + Drawing.restoreContext(); + return var5; + } + + private static void a306cl(final int var0, final int var3) { + for (int var9 = 0; var9 < 20; ++var9) { + final int var10 = var9 + 440; + int var11 = 5 - var9; + if (var11 < 0) { + var11 = 0; + } + + int var12 = -var9 + var3 + 20 - 5; + if (var3 < var12) { + var12 = var3; + } + + final int var13 = var12 - var11; + var11 += var0; + Drawing.horizontalLine(5 + var11, 5 + var10, var13, 0, 128); + } + + Drawing.horizontalLine(5 + var0, 440, -5 + var3, Drawing.WHITE); + Drawing.horizontalLine(var0, 20 + (440 - 1), 1 - 5 + var3, Drawing.WHITE); + + for (int var9 = 1; var9 < 20 - 1; ++var9) { + final int var10 = 440 + var9; + final int var11 = (var9 - 1) * 256 / (20 - 2); + final int var12 = var9 < 2 ? 10526880 : Drawing.alphaOver(4210752, 8421504, var11); + int var13 = 5 - var9; + if (var13 < 0) { + var13 = 0; + } + + int var14 = -5 + (20 + var3 - var9); + if (var14 > var3) { + var14 = var3; + } + + final int var15 = var14 - var13; + var13 += var0; + var14 += var0; + Drawing.setPixel(var13, var10, Drawing.WHITE); + Drawing.horizontalLine(1 + var13, var10, var15 - 4, var12); + Drawing.horizontalLine(var14 - 4, var10, 3, 10526880); + Drawing.setPixel(var14 - 1, var10, Drawing.WHITE); + } + } + + private static void initializeResources() { + Drawing.saveContext(); + INTRO_1_1 = SpriteResource.loadSprite(spriteLoader, "intro", "intro1_1"); + INTRO_1_2 = SpriteResource.loadSprite(spriteLoader, "intro", "intro1_2"); + INTRO_1_3 = SpriteResource.loadSprite(spriteLoader, "intro", "intro1_3"); + INTRO_1_FLASH = SpriteResource.loadSprite(spriteLoader, "intro", "intro1_flash"); + INTRO_1_GLOW = SpriteResource.loadSprite(spriteLoader, "intro", "intro1_glow"); + INTRO_1_GLOW_FG = SpriteResource.loadSprite(spriteLoader, "intro", "intro1_glow_fg"); + INTRO_1_3.installForDrawing(); + a455cle(Drawing.width, 0, 64, Drawing.height); + INTRO_1_2.installForDrawing(); + a455cle(Drawing.width, 0, 128, Drawing.height); + INTRO_1_1.installForDrawing(); + a669mws(Drawing.height, Drawing.width); + INTRO_2_EARTH = SpriteResource.loadSprite(spriteLoader, "intro", "intro2_earth"); + INTRO_2_CLOUDS = SpriteResource.loadSprite(spriteLoader, "intro", "intro2_clouds"); + a046ja(INTRO_2_EARTH.width / 2, INTRO_2_EARTH, INTRO_2_EARTH.height / 4); + a046ja(INTRO_2_CLOUDS.width / 2, INTRO_2_CLOUDS, INTRO_2_CLOUDS.height / 4); + _dsb = new Sprite(ShatteredPlansClient.SCREEN_WIDTH, 430); + _dsb.installForDrawing(); + + for (int var1 = 1; var1 < 64; ++var1) { + final int var2 = (int) (20.0D * Math.log(63.0F / (float) var1) / Math.log(2.0D)); + Drawing.fillCircle(320, 527, var2 + 400, (var1 << 2) * 65793); + } + + Drawing.b669(4, 4, Drawing.width, Drawing.height); + _mar = new Sprite(ShatteredPlansClient.SCREEN_WIDTH, 624 - INTRO_2_EARTH.y); + _mar.installForDrawing(); + + for (int var1 = 254; var1 >= 1; --var1) { + final int var2 = (int) (Math.log(254.0F / (float) var1) * 40.0D / Math.log(2.0D)); + INTRO_2_EARTH.e326(var2 - 5, var2 - INTRO_2_EARTH.y, var1 * 65793); + } + + INTRO_3_STARS = SpriteResource.loadSprite(spriteLoader, "intro", "intro3_stars"); + INTRO_3_CITY_BG = SpriteResource.loadSprite(spriteLoader, "intro", "intro3_citybg"); + INTRO_3_CITY_FG = SpriteResource.loadSprite(spriteLoader, "intro", "intro3_cityfg"); + INTRO_3_CRATER = SpriteResource.loadSprite(spriteLoader, "intro", "intro3_crater"); + _heh = new Sprite(INTRO_3_CITY_BG.width, INTRO_3_CITY_BG.height + 60); + + if (INTRO_3_CITY_BG.height * INTRO_3_CITY_BG.width >= 0) { + System.arraycopy(INTRO_3_CITY_BG.pixels, 0, _heh.pixels, INTRO_3_CITY_BG.width * 60, INTRO_3_CITY_BG.height * INTRO_3_CITY_BG.width); + } + + _heh.offsetX = INTRO_3_CITY_BG.offsetX; + _heh.x = INTRO_3_CITY_BG.x; + _heh.y = INTRO_3_CITY_BG.y - 60; + _heh.offsetY = 60 + INTRO_3_CITY_BG.offsetY; + _wef = new Sprite(INTRO_3_CITY_FG.width, 60 + INTRO_3_CITY_FG.height); + + if (INTRO_3_CITY_FG.height * INTRO_3_CITY_FG.width >= 0) { + System.arraycopy(INTRO_3_CITY_FG.pixels, 0, _wef.pixels, INTRO_3_CITY_FG.width * 60, INTRO_3_CITY_FG.height * INTRO_3_CITY_FG.width); + } + + _wef.x = INTRO_3_CITY_FG.x; + _wef.offsetY = INTRO_3_CITY_FG.offsetY + 60; + _wef.y = INTRO_3_CITY_FG.y - 60; + _wef.offsetX = INTRO_3_CITY_FG.offsetX; + _heh.installForDrawing(); + Drawing.b669(60, 60, _heh.width, _heh.height); + _wef.installForDrawing(); + Drawing.b669(60, 60, _wef.width, _wef.height); + _ksj = INTRO_3_STARS.copy(); + _ksj.d797(); + + for (int var3 = 0; var3 < _ksj.pixels.length; ++var3) { + final int var4 = _ksj.pixels[var3]; + final int var5 = 8323072 & var4 >> 1; + int var6 = (var5 >> 9 & 32512) + (var4 & '\uff00'); + var6 = var6 * 3 >> 1; + if (var6 <= 65280) { + var6 &= 65280; + } else { + var6 = 65280; + } + + final int var7 = 255 & var4; + _ksj.pixels[var3] = var6 | var5 | var7; + } + + _qqn = INTRO_2_EARTH.horizontallyFlipped(); + a332uo(_qqn); + final int var102 = _qqn.width; + final int var103 = _qqn.width + 120; + _tfb = new Sprite(var102, var103); + _tfb.installForDrawing(); + _qqn.e326(0, 120, 4259648); + Drawing.b669(120, 120, var102, var103); + Drawing.restoreContext(); + resourcesInitialized = true; + } + + private static void a150ph() { + if (_cbh != null) { + _cbh.removeIf(var1 -> var1._h < 0); + } + } + + private static void freeResources() { + resourcesInitialized = false; + INTRO_3_CRATER = null; + INTRO_1_GLOW = null; + _wef = null; + INTRO_1_3 = null; + _qqn = null; + INTRO_1_2 = null; + INTRO_3_STARS = null; + _ksj = null; + _tfb = null; + INTRO_2_EARTH = null; + INTRO_1_FLASH = null; + INTRO_1_GLOW_FG = null; + _mar = null; + INTRO_3_CITY_BG = null; + INTRO_2_CLOUDS = null; + _dsb = null; + INTRO_3_CITY_FG = null; + _heh = null; + INTRO_1_1 = null; + } + + private static void b150gq() { + for (final nd_ var3 : _feC) { + var3._h = 0; + var3._a = 0; + } + + _rpK.clear(); + } + + private static void b150ej() { + if (_cbh != null) { + final Iterator it = _cbh.iterator(); + + if (it.hasNext()) { + final RenderedTextLine var0 = it.next(); + if (++var0._h == 300) { + _cfe += (float) var0._i.height; + it.remove(); + } + } + + while (it.hasNext()) { + final RenderedTextLine var0 = it.next(); + if (++var0._h > 75) { + var0._h = 75; + } + } + + if (_cfe > 0.0F) { + _cfe *= 0.9F; + } + } + } + + private static void tickStage2() { + final int var0 = _dim * 100 / 1000 - 80; + final short var1 = 465; + final int var2 = 324 + var0 + 675; + + for (final nd_ var6 : _feC) { + if (var6._h != 0) { + var6._a += var6._h; + if (var6._a >= 200) { + var6._h = -var6._h; + float var7 = (float) (var6._e - var1) / 500.0F; + float var8 = (float) (var6._j - var2) / 500.0F; + var7 = (float) ((double) var7 + (Math.random() - 0.5D) / 5.0D); + var8 = (float) ((double) var8 + (Math.random() - 0.5D) / 5.0D); + _rpK.add(new sb_((float) (var6._e - 5), (float) (var0 + var6._j), var7 / 200.0F, var8 / 200.0F)); + } + + if (var6._a <= 0) { + var6._a = 0; + var6._h = 0; + } + } + + if (var6._a == 0 && ShatteredPlansClient.randomIntBounded(250) == 0 && _dim > 75) { + var6._h = 10; + } + } + + for (final sb_ var11 : _rpK) { + var11._o[var11._q] = var11._l; + var11._i[var11._q] = var11._n; + if (++var11._q == 50) { + var11._q = 0; + } + + var11._p += var11._r; + var11._m += var11._s; + var11._j += var11._m; + var11._k += var11._p; + var11._n += var11._j; + var11._l += var11._k; + } + + if (_dim == 0) { + a740sg(false, 100, StringConstants.TEXT_INTRO_2_START, currentFont); + a740sg(true, 800, StringConstants.TEXT_INTRO_2_END, currentFont); + } + + if (++_dim == 950) { + a366jc(3); + } + + } + + private static void tickStage3() { + if (_dim == 0) { + a740sg(false, 50, StringConstants.TEXT_INTRO_3_START, currentFont); + } + + if (++_dim == 750) { + a366jc(4); + } + } + + private static void tickStage4() { + if (_dim == 0) { + a740sg(false, 0, StringConstants.TEXT_INTRO_4_START, currentFont); + a740sg(false, 700, StringConstants.TEXT_INTRO_4_END, currentFont); + } + + if (++_dim == 950) { + a366jc(5); + } + + } + + private static void tickStage5() { + if (++_dim == 350) { + a366jc(-1); + } + + } + + private static void tickStage1() { + for (final nd_ var2 : _fey) { + if (var2._h != 0) { + var2._a += var2._h; + if (var2._a >= 100) { + var2._h = -var2._h; + } + + if (var2._a <= 0) { + var2._a = 0; + var2._h = 0; + } + } + + if (var2._a == 0 && ShatteredPlansClient.randomIntBounded(100) == 0) { + var2._h = 10; + } + } + + for (final nd_ var2 : _feH) { + if (var2._h != 0) { + var2._a += var2._h; + if (var2._a >= 100) { + var2._h = -var2._h; + } + + if (var2._a <= 0) { + var2._a = 0; + var2._h = 0; + } + } + + if (var2._a == 0 && ShatteredPlansClient.randomIntBounded(100) == 0) { + var2._h = 10; + } + } + + if (_dim == 0) { + a740sg(false, 0, StringConstants.TEXT_INTRO_1_START, currentFont); + a740sg(true, 400, StringConstants.TEXT_INTRO_1_END, currentFont); + } + + if (++_dim == 500) { + a366jc(2); + } + } + + private static void tickStage0() { + if (++_dim >= 200 && resourcesInitialized && !_pn) { + a366jc(1); + } + } + + private static void a669mws(int var2, int var4) { + final int var0 = 0; + final int var3 = 0; + + if (var0 + var2 > Drawing.height) { + var2 = Drawing.height - var0; + } + + if (var3 + var4 > Drawing.width) { + var4 = Drawing.width; + } + + final int var6 = 256; + final int var7 = var0 + var2; + + for (int var8 = var0; var8 < var7; ++var8) { + int var9 = Drawing.pixelIndex(var3, var8); + + for (int var10 = var4; var10 > 0; --var10) { + final int var11 = Drawing.screenBuffer[var9]; + final int r = (var11 & 0xff0000) >> 16; + final int g = (var11 & 0x00ff00) >> 8; + final int b = (var11 & 0x0000ff); + final int var15 = 5 * r - (-(g * 6) - 5 * b); + final int var16 = (var15 * var6 >> 12); + final int var17 = (var6 * var15 >> 12); + final int var18 = (var15 * var6 >> 12); + final int var19 = var16 << 16 | var17 << 8 | var18; + Drawing.screenBuffer[var9] = var19; + ++var9; + } + } + } + + private static void a366jc(final int var0) { + nextStage = var0; + _pn = true; + if (var0 == 1) { + ShatteredPlansClient.a827jo(Sounds.MUSIC_INTRO, 476, true); + } + } + + private static void a885tg(int var0, final Sprite var1) { + int var2 = -5 + var1.x; + var0 += var1.y; + int var3 = 0; + int var4 = 0; + int var5 = var1.width; + if (Drawing.left > var2) { + var5 += var2 - Drawing.left; + var3 = -var2 + Drawing.left; + var2 = Drawing.left; + } + + int var6 = var1.height; + if (var0 < Drawing.top) { + var4 = -var0 + Drawing.top; + var6 += -Drawing.top + var0; + var0 = Drawing.top; + } + + if (var5 + var2 > Drawing.right) { + var5 = Drawing.right - var2; + } + + if (var6 + var0 > Drawing.bottom) { + var6 = -var0 + Drawing.bottom; + } + + int var8 = var3 + var4 * var1.width; + final int var9 = -var5 + var1.width; + int var10 = Drawing.width * var0 + var2; + final int var11 = -var5 + Drawing.width; + + for (var0 = -var6; var0 < 0; ++var0) { + for (var2 = -var5; var2 < 0; ++var2) { + int var12 = 255 & var1.pixels[var8++]; + if (var12 == 0) { + ++var10; + } else { + int var13 = Drawing.screenBuffer[var10]; + if (var12 == 255) { + var13 = 8355711 & var13 >>> 1 | 8421504; + } else { + var12 >>= 2; + int var14 = var13 & '\uff00'; + var13 &= 16711935; + var13 *= 256 - var12; + var13 &= -16711936; + var14 *= 256 - var12; + var14 &= 16711680; + var13 = (var13 | var14) >>> 8; + var13 += var12 * 65793; + } + + Drawing.screenBuffer[var10++] = var13; + } + } + + var8 += var9; + var10 += var11; + } + + } + + private static void a740sg(final boolean var0, int var1, final String var2, final Font font) { + if (_cbh == null) { + _cbh = new ArrayList<>(); + } + + final String[] strs = new String[32]; + final int var5 = font.breakLines(var2, new int[]{600}, strs); + if (var0) { + var1 -= var5 * 50; + } + + for (int i = 0; i < var5; ++i) { + _cbh.add(new RenderedTextLine(strs[i], font, i * 50 + var1)); + } + } + + private static void a046ja(final int var1, final Sprite var2, final int var3) { + int var4 = -1; + final int var5 = var2.width; + final int var6 = Math.max(-var1 + var5, var1); + + final int var7 = var2.height; + int var8 = var3; + if (var3 < -var3 + var7) { + var8 = var7 - var3; + } + + for (int var9 = 0; var9 < var7; ++var9) { + for (int var10 = 0; var5 > var10; ++var10) { + ++var4; + final int var11 = var2.pixels[var4]; + if (var11 != 0) { + float var12 = (float) ((-var1 + var10) * (var10 - var1) + (-var3 + var9) * (-var3 + var9)); + var12 /= (float) (MathUtil.euclideanDistanceSquared(var8, var6)); + final int var13 = (int) (256.0F * (-((float) Math.sqrt(var12)) + 1.0F)); + if (var13 > 0) { + if (var13 <= 255) { + int var14 = var11 & 16711935; + var14 *= var13; + int var15 = '\uff00' & var11; + var15 *= var13; + final int i = (16711680 & var15 | -16711936 & var14) >>> 8; + var2.pixels[var4] = i != 0 ? i : 1; + } + } else { + var2.pixels[var4] = 1; + } + } + } + } + } + + private static void draw(final Sprite sprite, final int x, final int y, final int alpha, final int var0) { + if (var0 >= 128) { + Drawing.setBounds(x, 0, x + var0 - 128, y + ShatteredPlansClient.SCREEN_HEIGHT); + sprite.drawAdd(x, y, alpha); + } + + final int var5 = var0 < 128 ? 0 : var0 - 128; + + for (int var7 = var5; var0 > var7; ++var7) { + Drawing.setBounds(x + var7, 0, x + var7 + 1, ShatteredPlansClient.SCREEN_HEIGHT + y); + final int var8 = alpha * (-var7 + var0) >> 7; + sprite.drawAdd(x, y, var8); + } + + Drawing.a797(); + } + + private static void a332uo(final Sprite var0) { + final int var1 = 32768; + int var3 = -1; + + for (int var4 = -var0.height; var4 < 0; ++var4) { + for (int var5 = -var0.width; var5 < 0; ++var5) { + ++var3; + final int var6 = var0.pixels[var3]; + if (var6 != 0) { + final int var7 = ((var6 & 16711680) >> 16) + (var6 & 255) + (('\uff00' & var6) >> 7) >> 2; + int i = (var1 * var7 & 16711680) >>> 8; + if (i == 0) { + i = 1; + } + + var0.pixels[var3] = i; + } + } + } + } +} diff --git a/src/main/java/funorb/shatteredplans/client/intro/RenderedTextLine.java b/src/main/java/funorb/shatteredplans/client/intro/RenderedTextLine.java new file mode 100644 index 0000000..60ef5dd --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/intro/RenderedTextLine.java @@ -0,0 +1,44 @@ +package funorb.shatteredplans.client.intro; + +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.graphics.Sprite; + +public final class RenderedTextLine { + public final Sprite _o; + public final Sprite _i; + public int _h; + + public RenderedTextLine(final String str, final Font font, final int var3) { + int width = font.measureLineWidth(str); + final int height = font.ascent + font.descent; + final boolean var6 = width > 500; + if (var6) { + width = 600; + } + + this._i = new Sprite(width, height); + this._o = new Sprite(width + 6, height + 6); + Drawing.saveContext(); + + this._i.installForDrawing(); + if (var6) { + font.drawJustified(str, 0, font.ascent, 600); + } else { + font.draw(str, 0, font.ascent, Drawing.WHITE); + } + + this._o.installForDrawing(); + this._i.c093(3, 3); + Drawing.b669(1, 1, width + 6, height + 6); + + for (int i = (width + 6) * (height + 6) - 1; i >= 0; --i) { + if ((Drawing.screenBuffer[i] & 0x80) == 0) { + Drawing.screenBuffer[i] <<= 1; + } + } + Drawing.restoreContext(); + + this._h = -var3; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/intro/nd_.java b/src/main/java/funorb/shatteredplans/client/intro/nd_.java new file mode 100644 index 0000000..c3ce5d1 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/intro/nd_.java @@ -0,0 +1,15 @@ +package funorb.shatteredplans.client.intro; + +public final class nd_ { + public final int _e; + public final int _f; + public final int _j; + public int _a; + public int _h; + + public nd_(final int var1, final int var2, final int var3) { + this._j = var2; + this._f = var3; + this._e = var1; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/intro/sb_.java b/src/main/java/funorb/shatteredplans/client/intro/sb_.java new file mode 100644 index 0000000..f0e4939 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/intro/sb_.java @@ -0,0 +1,34 @@ +package funorb.shatteredplans.client.intro; + +public final class sb_ { + public final float[] _i; + public final float[] _o = new float[50]; + public final float _r; + public final float _s; + public float _p; + public float _k; + public float _n; + public float _m; + public float _j; + public int _q; + public float _l; + + public sb_(final float var1, final float var2, final float var5, final float var6) { + this._s = (float) 0.0; + this._n = var2; + this._r = (float) 0.0; + this._m = var6; + this._j = (float) 0.0; + this._p = var5; + this._i = new float[50]; + this._l = var1; + this._k = (float) 0.0; + + for (int var9 = 0; var9 < 50; ++var9) { + this._o[var9] = this._l; + this._i[var9] = this._n; + } + + this._q = 0; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/ui/Button.java b/src/main/java/funorb/shatteredplans/client/ui/Button.java new file mode 100644 index 0000000..2caab73 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/ui/Button.java @@ -0,0 +1,72 @@ +package funorb.shatteredplans.client.ui; + +import funorb.graphics.Sprite; +import funorb.shatteredplans.client.Menu; + +public final class Button extends UIComponent { + private final Sprite inactiveIcon; + private final String inactiveLabel; + private final int inactiveLabelColor; + + private final Sprite activeIcon; + private final String activeLabel; + private final int activeLabelColor; + + private boolean isActive = false; + + public Button(final int x, + final int y, + final int width, + final int height, + final Sprite inactiveIcon, + final String inactiveLabel, + final int inactiveLabelColor, + final Sprite activeIcon, + final String activeLabel, + final int activeLabelColor) { + super(x, y, width, height); + this.inactiveIcon = inactiveIcon; + this.inactiveLabel = inactiveLabel; + this.inactiveLabelColor = inactiveLabelColor; + this.activeIcon = activeIcon; + this.activeLabel = activeLabel; + this.activeLabelColor = activeLabelColor; + } + + public boolean isActive() { + return this.isActive; + } + + public void deactivate() { + this.isActive = false; + } + + public void activate() { + this.isActive = true; + } + + public void toggle() { + this.isActive = !this.isActive; + } + + @Override + public void draw() { + if (this.visible) { + if (this.isActive) { + if (this.activeIcon != null) { + this.activeIcon.draw(this.x + (this.width - this.activeIcon.width) / 2, (this.height - this.activeIcon.height) / 2 + this.y); + } + if (this.activeLabel != null) { + Menu.SMALL_FONT.drawCentered(this.activeLabel, this.width / 2 + 1 + this.x, Menu.SMALL_FONT.ascent / 2 + this.height / 2 + this.y, this.activeLabelColor); + } + } else { + if (this.inactiveIcon != null) { + this.inactiveIcon.draw((-this.inactiveIcon.width + this.width) / 2 + this.x, (this.height - this.inactiveIcon.height) / 2 + this.y); + } + if (this.inactiveLabel != null) { + Menu.SMALL_FONT.drawCentered(this.inactiveLabel, this.width / 2 + 1 + this.x, Menu.SMALL_FONT.ascent / 2 + this.height / 2 + this.y, this.inactiveLabelColor); + } + } + } + } +} diff --git a/src/main/java/funorb/shatteredplans/client/ui/ChatMessage.java b/src/main/java/funorb/shatteredplans/client/ui/ChatMessage.java new file mode 100644 index 0000000..e245645 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/ui/ChatMessage.java @@ -0,0 +1,40 @@ +package funorb.shatteredplans.client.ui; + +import funorb.graphics.Drawing; +import funorb.shatteredplans.client.GameUI; + +public final class ChatMessage { + private final String text; + private final int width; + private int age = 0; + private int alpha = 256; + + public ChatMessage(final String text) { + this.text = text; + this.width = Math.max(GameUI._ssb.measureLineWidth(this.text) + 20, 400); + } + + public void tick() { + if (this.age >= 600) { + this.alpha = 0; + } else { + ++this.age; + if (this.age > 500) { + final int var2 = 100 - this.age + 500; + this.alpha = (var2 << 8) / 100; + } + } + } + + public void draw(final int y) { + if (this.alpha != 0) { + Drawing.fillRoundedRect(88, y + 1, this.width, 17, 6, Drawing.BLACK, this.alpha); + + if (this.alpha == 256) { + GameUI._ssb.draw(this.text, 100, y + 14, Drawing.WHITE); + } else { + GameUI._ssb.draw(this.text, 100, y + 14, Drawing.WHITE, this.alpha); + } + } + } +} diff --git a/src/main/java/funorb/shatteredplans/client/ui/DiplomacyPanelState.java b/src/main/java/funorb/shatteredplans/client/ui/DiplomacyPanelState.java new file mode 100644 index 0000000..0a92c18 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/ui/DiplomacyPanelState.java @@ -0,0 +1,16 @@ +package funorb.shatteredplans.client.ui; + +import funorb.shatteredplans.game.Player; + +public final class DiplomacyPanelState implements PanelState { + public final ScrollView[] _h; + public final fe_[] _i; + public final Icon[][] _f; + + @SuppressWarnings("unchecked") + public DiplomacyPanelState(final int var1) { + this._h = new ScrollView[var1]; + this._f = new Icon[var1][var1 - 1]; + this._i = new fe_[var1 - 1]; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/ui/FixedPanel.java b/src/main/java/funorb/shatteredplans/client/ui/FixedPanel.java new file mode 100644 index 0000000..aede693 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/ui/FixedPanel.java @@ -0,0 +1,62 @@ +package funorb.shatteredplans.client.ui; + +import funorb.graphics.Drawing; + +import java.util.ListIterator; + +public final class FixedPanel extends UIComponent { + public PanelState state; + + public FixedPanel(final int x, final int y, final int width, final int height) { + super(x, y, width, height); + } + + private static void a050er(final int var0, final int var1, final int var2, final int var3) { + FloatingPanel.a669am(var2, 0x3ca4a7, var1, var0, var3); + } + + @Override + public void draw() { + if (this.visible) { + final int[] var2 = new int[4]; + Drawing.saveBoundsTo(var2); + Drawing.fillRoundedRect(this.x, this.y, this.width, this.height, 10, 0, 200); + a050er(this.x, this.height, this.width - 10, this.y); + Drawing.horizontalLine(10 + this.x, this.y, this.width - 20, 2052949); + Drawing.horizontalLine(this.x + 10, this.y + this.height, this.width - 20, 0); + Drawing.expandBoundsToInclude(this.x, this.y, this.x + 10, this.y + 10); + Drawing.strokeCircle(10 + this.x, 10 + this.y, 10, 2052949); + Drawing.restoreBoundsFrom(var2); + Drawing.expandBoundsToInclude(this.width + (this.x - 10), this.y, this.width + this.x, this.y + 10); + Drawing.strokeCircle(this.width + (this.x - 10 - 1), this.y + 10, 10, 2052949); + Drawing.restoreBoundsFrom(var2); + Drawing.expandBoundsToInclude(this.x, this.height + this.y - 10, this.x + 10, this.y + this.height); + Drawing.strokeCircle(this.x + 10, this.y - (-this.height + 10 + 1), 10, 0); + Drawing.restoreBoundsFrom(var2); + Drawing.expandBoundsToInclude(this.width + (this.x - 10), this.height + this.y - 10, this.x + this.width, this.y + this.height); + Drawing.strokeCircle(this.x - 1 - (-this.width + 10), this.y - (-this.height + 10) - 1, 10, 0); + Drawing.restoreBoundsFrom(var2); + + for (int var3 = 0; var3 < 3 * (this.height - 10) / 4; ++var3) { + final int var5 = Drawing.alphaOver(0, 0x1f5355, 256 * var3 / (3 * (this.height - 10) / 4)); + Drawing.setPixel(this.x, var3 + 10 + this.y, var5); + Drawing.setPixel(this.width + this.x - 1, var3 + this.y + 10, var5); + } + + for (final ListIterator> it = this.children.listIterator(this.children.size()); it.hasPrevious(); ) { + final UIComponent var4 = it.previous(); + var4.draw(); + } + } + } + + @Override + public UIComponent findMouseTarget(final int x, final int y) { + if (this.visible) { + final UIComponent var4 = UIComponent.findMouseTarget(this.children, x, y); + return var4 != null ? var4 : super.findMouseTarget(x, y); + } else { + return null; + } + } +} diff --git a/src/main/java/funorb/shatteredplans/client/ui/FloatingPanel.java b/src/main/java/funorb/shatteredplans/client/ui/FloatingPanel.java new file mode 100644 index 0000000..66472e6 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/ui/FloatingPanel.java @@ -0,0 +1,215 @@ +package funorb.shatteredplans.client.ui; + +import funorb.graphics.Drawing; +import funorb.shatteredplans.client.Menu; +import funorb.shatteredplans.client.ShatteredPlansClient; + +import java.util.ListIterator; + +public final class FloatingPanel extends UIComponent { + private final String title; + public T state; + public boolean flashing; + public ScrollView content; + + public FloatingPanel(final int x, final int y, final int width, final int height, final String title) { + super(x, y, width, height); + this.title = title; + this.a183(height, width); + this.enabled = true; + this.visible = false; + this.flashing = false; + } + + public static void a669am(final int var0, final int var1, final int var3, final int var4, final int var5) { + final int var6 = var3 / 10 + 1; + final int var7 = 96 / var6; + a676kfl(96, var0, 96 - var7, var4, var5, false, var1); + int var8 = 96; + + for (int var9 = 1; var9 < var6; ++var9) { + var8 -= var7; + a676kfl(var8, var0, -var7 + var8, var4, var9 * 10 + var5, true, var1); + } + } + + private static void a676kfl(final int var0, final int var2, final int var3, final int var4, final int var5, final boolean var6, final int var7) { + int var8; + int var9; + for (var9 = 7; var2 > var9; var9 += 16) { + var8 = var6 ? 4 : 6; + if (1 + var9 + var8 >= var2) { + var8 = var2 - var9 - 1; + } + + Drawing.horizontalLine((!var6 ? 0 : 1) + var4 + var9, var5 + 1, var8, var7, var0 * (var2 - var9 * var9 / var2) / var2); + } + + for (var9 = 4; var9 < var2; var9 += 16) { + Drawing.line(var4 + var9, var5 + 6, var4 + var9 + 3, var5 + 1, var7, var0 * (var2 - var9 * var9 / var2) / var2); + Drawing.line(3 + var4 + var9, 11 + var5, var9 + var4, 6 + var5, var7, (var3 + var0) * (-(var9 * var9 / var2) + var2) / 2 / var2); + } + + for (var9 = 12; var2 > var9; var9 += 16) { + Drawing.line(3 + var4 + var9, 6 + var5, var4 + var9, 1 + var5, var7, var0 * (-(var9 * var9 / var2) + var2) / var2); + Drawing.line(var4 + var9, var5 + 11, var4 + var9 + 3, var5 + 6, var7, (var0 + var3) * (-(var9 * var9 / var2) + var2) / 2 / var2); + } + + Drawing.h669(1 + var4, var5 + 6, var4 + 3, var5 + 6, var7, (var0 + var3) / 2); + + for (var9 = 16; var9 < var2; var9 += 16) { + var8 = 4; + if (var2 <= 1 + var8 + var9) { + var8 = var2 - var9 - 1; + } + + Drawing.horizontalLine(var9 + var4, 6 + var5, var8, var7, (var0 + var3) * (var2 - var9 * var9 / var2) / 2 / var2); + } + + } + + @Override + public void draw() { + if (this.visible) { + int var3 = 2052949; + int var4 = 1125164; + int var5 = 3974311; + int var6; + if (this.flashing) { + var6 = ShatteredPlansClient.currentTick % 64; + if (var6 > 24 && var6 <= 40) { + var6 = 24; + } + + if (var6 > 40) { + var6 = 64 - var6; + } + + var6 *= 10; + var3 = Drawing.alphaOver(12993090, 2052949, var6); + var4 = Drawing.alphaOver(12993090, var4, var6); + var5 = Drawing.alphaOver(12993090, var5, var6); + } + + Drawing.fillRoundedRect(this.x, this.y, this.width, this.height, 10, 0, 200); + a669am(this.width - 10, var5, 15, this.x, this.y); + Drawing.horizontalLine(10 + this.x, this.y, this.width - 20, var3); + Drawing.horizontalLine(10 + this.x, this.height + this.y, this.width - 20, 0); + Drawing.setBounds(this.x, this.y, this.x + 10, this.y + 10); + Drawing.strokeCircle(this.x + 10, this.y + 10, 10, var3); + Drawing.setBounds(this.x + this.width - 10, this.y, this.width + this.x, 10 + this.y); + Drawing.strokeCircle(this.width - 1 + (this.x - 10), this.y + 10, 10, var3); + Drawing.setBounds(this.x, this.y - 10 + this.height, this.x + 10, this.y + this.height); + Drawing.strokeCircle(10 + this.x, this.y + this.height - 10 - 1, 10, 0); + Drawing.setBounds(this.width + this.x - 10, this.y + this.height - 10, this.width + this.x, this.y + this.height); + Drawing.strokeCircle(this.x + this.width - 11, this.height + (this.y - 10 - 1), 10, 0); + Drawing.a797(); + + int var7; + for (var6 = 0; var6 < this.height - 20; ++var6) { + var7 = Drawing.alphaOver(0, var3, var6 * 256 / (this.height - 20)); + Drawing.setPixel(this.x, var6 + this.y + 10, var7); + Drawing.setPixel(this.width + (this.x - 1), this.y + 10 + var6, var7); + } + + Drawing.fillRoundedRect(3 + this.x, 15 + this.y, this.width - 6, this.height - 15 - 3, 10, 0); + Drawing.horizontalLine(3 + 10 + this.x, 15 + this.y, this.width - 20 - 6, var3); + Drawing.horizontalLine(10 + this.x + 3, this.y - 3 - (-this.height + 1), this.width - 20 - 6, var4); + Drawing.setBounds(this.x + 3, this.y + 15, 3 + this.x + 10, this.y + 25); + Drawing.strokeCircle(13 + this.x, 25 + this.y, 10, var3); + Drawing.setBounds(this.width - 3 + (this.x - 10), 15 + this.y, this.x - 3 + this.width, this.y + 15 + 10); + Drawing.strokeCircle(this.width + (this.x - 14), this.y + 25, 10, var3); + Drawing.setBounds(3 + this.x, this.height + this.y - 13, this.x + 10 + 3, this.y + this.height - 3); + Drawing.strokeCircle(3 + this.x + 10, this.y - 10 + this.height - 4, 10, var4); + Drawing.setBounds(this.width + this.x - 13, this.height + this.y - 13, this.width - 3 + this.x, this.y - (-this.height + 3)); + Drawing.strokeCircle(this.width - 10 + (this.x - 4), this.y - 3 + this.height - 10 - 1, 10, var4); + Drawing.a797(); + + for (var6 = 0; 2 * (this.height - 38) / 3 > var6; ++var6) { + var7 = Drawing.alphaOver(0, var3, 256 * var6 / ((2 * this.height - 76) / 3)); + Drawing.setPixel(this.x + 3, this.y + 25 + var6, var7); + Drawing.setPixel(this.x - 1 - (-this.width + 3), var6 + this.y + 15 + 10, var7); + } + + var6 = (this.height * 2 - 76) / 3; + + int var8; + for (var7 = 0; -var6 + this.height - 38 > var7; ++var7) { + var8 = Drawing.alphaOver(var4, 0, 256 * var7 / (this.height - 38 - var6)); + Drawing.setPixel(this.x + 3, var6 + var7 + 15 + this.y + 10, var8); + Drawing.setPixel(this.x + this.width - 3 - 1, 25 + this.y - (-var7 - var6), var8); + } + + Menu.SHINE_LEFT.drawAdd(4 + this.x, this.y + 3, 256); + var7 = Menu.SHINE_LEFT.width + 1 + this.x + 3; + var8 = -Menu.SHINE_RIGHT.width - 3 + this.width + this.x; + Menu.SHINE_RIGHT.drawAdd(var8, 3 + this.y, 64); + + for (int var10 = var7; var10 < var8; ++var10) { + final int var9 = 64 + 192 * (-var10 + var8) / (var8 - var7); + Menu.SHINE_MID.drawAdd(var10, this.y + 3, var9); + } + + Menu.SMALL_FONT.drawCentered(this.title, this.x + this.width / 2, this.y + 12, Drawing.WHITE); + + for (final ListIterator> it = this.children.listIterator(this.children.size()); it.hasPrevious(); ) { + final UIComponent var11 = it.previous(); + var11.draw(); + } + } + } + + @Override + public UIComponent findMouseTarget(final int x, final int y) { + if (this.visible) { + final UIComponent var4 = UIComponent.findMouseTarget(this.children, x, y); + return var4 == null ? super.findMouseTarget(x, y) : var4; + } else { + return null; + } + } + + @Override + public void a183(int var2, int var3) { + if (var2 < 39) { + var2 = 39; + } + + if (var3 < 27) { + var3 = 27; + } + + if (var3 < 40 + Menu.SMALL_FONT.measureLineWidth(this.title + "X")) { + var3 = Menu.SMALL_FONT.measureLineWidth(this.title + "X") + 40; + } + + this.width = var3; + this.height = var2; + } + + @Override + public void handleDrag(final int mouseX, final int mouseY, final int originX, final int originY) { + final int var4 = mouseX + originX; + final int var5 = mouseY + originY; + + int var6 = -this.x + var4; + if (this.x + var6 < -this.width / 2) { + var6 = -this.x + -this.width / 2; + } + + int var7 = var5 - this.y; + if (-(this.width / 2) + ShatteredPlansClient.SCREEN_WIDTH < var6 + this.x) { + var6 = -(this.width / 2) + (ShatteredPlansClient.SCREEN_WIDTH - this.x); + } + + if (this.y + var7 < 0) { + var7 = -this.y; + } + + if (var7 + this.y > 465) { + var7 = 465 - this.y; + } + + this.translate(var6, var7); + } +} diff --git a/src/main/java/funorb/shatteredplans/client/ui/Icon.java b/src/main/java/funorb/shatteredplans/client/ui/Icon.java new file mode 100644 index 0000000..4290b9e --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/ui/Icon.java @@ -0,0 +1,37 @@ +package funorb.shatteredplans.client.ui; + +import funorb.graphics.Sprite; + +public final class Icon extends UIComponent { + private Sprite sprite; + + public Icon(final int x, final int y, final Sprite sprite) { + this(x, y, sprite.width, sprite.height, sprite); + } + + public Icon(final int x, final int y, final int width, final int height, final Sprite sprite) { + super(x, y, width, height); + this.sprite = sprite; + } + + public void setSprite(final Sprite sprite) { + this.sprite = sprite; + } + + public boolean isEmpty() { + return this.sprite == null; + } + + @Override + public void draw() { + if (this.visible) { + if (this.sprite != null) { + if (this.width == this.sprite.width && this.height == this.sprite.height) { + this.sprite.draw(this.x, this.y); + } else { + this.sprite.b115(this.x, this.y, this.width, this.height); + } + } + } + } +} diff --git a/src/main/java/funorb/shatteredplans/client/ui/Label.java b/src/main/java/funorb/shatteredplans/client/ui/Label.java new file mode 100644 index 0000000..06f6e08 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/ui/Label.java @@ -0,0 +1,33 @@ +package funorb.shatteredplans.client.ui; + +import funorb.graphics.Drawing; +import funorb.shatteredplans.game.Force; +import funorb.shatteredplans.client.Menu; + +public class Label extends UIComponent { + private final int color; + public String text; + + public Label(final int x, final int y, final String text) { + this(x, y, Menu.SMALL_FONT.measureLineWidth(text), Menu.SMALL_FONT.ascent, text); + } + + public Label(final int x, final int y, final int width, final int height, final String text) { + this(x, y, width, height, text, Drawing.WHITE); + } + + public Label(final int x, final int y, final int width, final int height, final String text, final int color) { + super(x, y, width, height); + this.text = text; + this.color = color; + } + + @Override + public void draw() { + if (this.visible) { + if (this.text != null) { + Menu.SMALL_FONT.drawCentered(this.text, this.width / 2 + this.x, 3 * Menu.SMALL_FONT.ascent / 4 + this.y, this.color); + } + } + } +} diff --git a/src/main/java/funorb/shatteredplans/client/ui/MultilineLabel.java b/src/main/java/funorb/shatteredplans/client/ui/MultilineLabel.java new file mode 100644 index 0000000..9b4c96f --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/ui/MultilineLabel.java @@ -0,0 +1,30 @@ +package funorb.shatteredplans.client.ui; + +import funorb.graphics.Drawing; +import funorb.graphics.Font; +import funorb.shatteredplans.client.Menu; +import funorb.shatteredplans.client.ShatteredPlansClient; + +public final class MultilineLabel extends Label { + private Font.HorizontalAlignment horizontalAlignment; + + @SuppressWarnings("SameParameterValue") + public MultilineLabel(final int x, final int y, final int width, final int height, final Font.HorizontalAlignment horizontalAlignment) { + super(x, y, width, height, null); + this.horizontalAlignment = horizontalAlignment; + } + + @Override + public void draw() { + if (this.visible) { + if (this.text != null) { + Menu.SMALL_FONT.drawParagraph(this.text, this.x, this.y, this.width, ShatteredPlansClient.SCREEN_HEIGHT, Drawing.WHITE, this.horizontalAlignment, Font.VerticalAlignment.TOP, Menu.SMALL_FONT.ascent); + } + } + } + + public void setTextAndLeftAlign(final String text) { + this.text = text; + this.horizontalAlignment = Font.HorizontalAlignment.LEFT; + } +} diff --git a/src/main/java/funorb/shatteredplans/client/ui/PanelState.java b/src/main/java/funorb/shatteredplans/client/ui/PanelState.java new file mode 100644 index 0000000..c93ee38 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/ui/PanelState.java @@ -0,0 +1,4 @@ +package funorb.shatteredplans.client.ui; + +public interface PanelState { +} diff --git a/src/main/java/funorb/shatteredplans/client/ui/ProductionPanelState.java b/src/main/java/funorb/shatteredplans/client/ui/ProductionPanelState.java new file mode 100644 index 0000000..992ba93 --- /dev/null +++ b/src/main/java/funorb/shatteredplans/client/ui/ProductionPanelState.java @@ -0,0 +1,62 @@ +package funorb.shatteredplans.client.ui; + +import funorb.Strings; +import funorb.shatteredplans.StringConstants; +import funorb.shatteredplans.game.Force; + +import java.util.List; + +public final class ProductionPanelState implements PanelState { + public List> _f; + public List> buildFleetsButtons; + public List